Migrate web builds from Vue CLI to Vite
This commit changes the web application's build, transpilation and minification process from Vue CLI to Vite. This shift paves the way for a full migration to Vite as the primary build tool (#230). Configuration changes: - `.vscode/extensions.json`: Update recommended plugins, replacing unmaintained ones with official recommendations. - Legacy browser support: - Use `@vitejs/plugin-legacy` to transpile for older browsers. - Remove `core-js` dependency and `babel.config.cjs` configuration as they're now handled by the legacy plugin. - Delete `@babel/preset-typescript` and `@babel/preset-typescript` dependencies as legacy plugin handles babel dependencies by default. - Add `terser` dependency that's used by the legacy plugin for minification, as per Vite's official documentation. - `tsconfig.json`: - Remove obsolete `webpack-env` types. - Add `"resolveJsonModule": true` to be able to read JSON files in right way. - Use correct casing as configuration values. - Simplify `lib` to align with Vite and Vue starter configuration. - Add `"skipLibCheck": true` as `npm run build` now runs `tsc` which fails on inconsistent typings inside `node_modules` due to npm's weak dependency resoultion. - PostCSS: - Add `autoprefixer` as dependency, no longer installed by Vue CLI. - Epxlicitly added `postcss` as dependency to anticipate potential peer dependency changes. - Remove related `@vue/cli` dependencies. - Remove `sass-loader` as Vite has native CSS preprocessing support. - Run integration tests with `jsdom` environment so `window` object can be used. Client-side changes: - Abstract build tool specific environment variable population. Environment variables were previously populated by Vue CLI and now by Vite but not having an abstraction caused issues. This abstraction solves build errors and allows easier future migrations and testing. - Change Vue CLI-specific `~@` aliases to `@` to be able to compile with Vite. - Update types in LiquorTree to satisfy `tsc`. - Remove Vue CLI-specific workaround from `src/presentation/main.ts`. Restructuring: - Move `public/` to `presentation/` to align with the layered structure, which was not possible with Vue CLI. - Move `index.html` to web root instead of having it inside `public/` to align with official recommended structure. - Move logic shared by both integration and unit tests to `tests/shared`. - Move logo creation script to `scripts/` and its npm command to include `build` to align with rest of the structure.
This commit is contained in:
@@ -10,7 +10,6 @@ module.exports = {
|
||||
},
|
||||
extends: [
|
||||
// Vue specific rules, eslint-plugin-vue
|
||||
// Added by Vue CLI
|
||||
'plugin:vue/essential',
|
||||
|
||||
// Extends eslint-config-airbnb
|
||||
@@ -18,7 +17,6 @@ module.exports = {
|
||||
|
||||
// Extends @typescript-eslint/recommended
|
||||
// Uses the recommended rules from the @typescript-eslint/eslint-plugin
|
||||
// Added by Vue CLI
|
||||
'@vue/typescript/recommended',
|
||||
],
|
||||
rules: {
|
||||
|
||||
10
.github/workflows/checks.build.yaml
vendored
10
.github/workflows/checks.build.yaml
vendored
@@ -9,7 +9,13 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ macos, ubuntu, windows ]
|
||||
mode: [ development, test, production ]
|
||||
mode: [
|
||||
# Vite mode: https://vitejs.dev/guide/env-and-mode.html
|
||||
development, # Used by `dev` command
|
||||
production, # Used by `build` command
|
||||
# Vitest mode: https://vitest.dev/guide/cli.html
|
||||
test, # Used by Vitest
|
||||
]
|
||||
fail-fast: false # Allows to see results from other combinations
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
steps:
|
||||
@@ -72,4 +78,4 @@ jobs:
|
||||
run: npm ci
|
||||
-
|
||||
name: Create icons
|
||||
run: npm run create-icons
|
||||
run: npm run icons:build
|
||||
|
||||
4
.vscode/extensions.json
vendored
4
.vscode/extensions.json
vendored
@@ -11,8 +11,8 @@
|
||||
"dbaeumer.vscode-eslint", // Lints JavaScript/TypeScript.
|
||||
"pmneo.tsimporter", // Provides better auto-complete for TypeScripts imports.
|
||||
// Vue
|
||||
"jcbuisson.vue", // Highlights syntax.
|
||||
"octref.vetur", // Adds Vetur, Vue tooling support.
|
||||
"Vue.volar", // Official Vue extensions
|
||||
"Vue.vscode-typescript-vue-plugin", // Official TypeScript Vue Plugin
|
||||
// Scripting
|
||||
"timonwong.shellcheck", // Lints bash files.
|
||||
"ms-vscode.powershell", // Lints PowerShell files.
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset',
|
||||
],
|
||||
};
|
||||
@@ -35,7 +35,7 @@ Application layer enables [data-driven programming](https://en.wikipedia.org/wik
|
||||
|
||||
Application layer parses the application data to compile the domain object [`Application.ts`](./../src/domain/Application.ts).
|
||||
|
||||
A webpack loader loads (or injects) application data ([collection yaml files](./../src/application/collections/)) into the application layer in compile time. Application layer ([`ApplicationFactory.ts`](./../src/application/ApplicationFactory.ts)) parses and compiles this data in runtime.
|
||||
The build tool loads (or injects) application data ([collection yaml files](./../src/application/collections/)) into the application layer in compile time. Application layer ([`ApplicationFactory.ts`](./../src/application/ApplicationFactory.ts)) parses and compiles this data in runtime.
|
||||
|
||||
Application layer compiles templating syntax during parsing to create the end scripts. You can read more about templating syntax in [templating.md](./templating.md) and how application data uses them through functions in [collection-files.md | Function](./collection-files.md#function).
|
||||
|
||||
|
||||
@@ -35,11 +35,18 @@ You could run other types of tests as well, but they may take longer time and ov
|
||||
|
||||
### Running
|
||||
|
||||
- Run in local server: `npm run serve`
|
||||
**Web:**
|
||||
|
||||
- Run in local server: `npm run dev`
|
||||
- 💡 Meant for local development with features such as hot-reloading.
|
||||
- Run using Docker:
|
||||
1. Build: `docker build -t undergroundwires/privacy.sexy:latest .`
|
||||
2. Run: `docker run -it -p 8080:80 --rm --name privacy.sexy undergroundwires/privacy.sexy:latest`
|
||||
- Preview production build: `npm run preview`
|
||||
- Start a local web server that serves the built solution from `./dist`.
|
||||
- 💡 Run `npm run build` before `npm run preview`.
|
||||
|
||||
**Docker:**
|
||||
|
||||
1. Build: `docker build -t undergroundwires/privacy.sexy:latest .`
|
||||
2. Run: `docker run -it -p 8080:80 --rm --name privacy.sexy undergroundwires/privacy.sexy:latest`
|
||||
|
||||
### Building
|
||||
|
||||
|
||||
@@ -10,24 +10,23 @@ The presentation layer uses an event-driven architecture for bidirectional react
|
||||
|
||||
## Structure
|
||||
|
||||
- [`/src/` **`presentation/`**](./../src/presentation/): Contains all presentation related code including Vue and Electron configurations
|
||||
- [**`bootstrapping/`**](./../src/presentation/bootstrapping/): Registers Vue global objects including components and plugins.
|
||||
- [**`components/`**](./../src/presentation/components/): Contains all Vue components and their helper classes.
|
||||
- [**`Shared/`**](./../src/presentation/components/Shared): Contains Vue components and component helpers that other components share.
|
||||
- [**`hooks`**](../src/presentation/components/Shared/Hooks): Shared hooks for state access
|
||||
- [**`assets/`**](./../src/presentation/assets/styles/): Contains assets that webpack will process.
|
||||
- [**`fonts/`**](./../src/presentation/assets/fonts/): Contains fonts
|
||||
- [**`styles/`**](./../src/presentation/assets/styles/): Contains shared styles used throughout different components.
|
||||
- [**`components/`**](./../src/presentation/assets/styles/components): Contains reusable styles coupled to a Vue/HTML component.
|
||||
- [**`vendors-extensions/`**](./../src/presentation/assets/styles/third-party-extensions): Contains styles that override third-party components used.
|
||||
- [**`main.scss`**](./../src/presentation/assets/styles/main.scss): Primary Sass file, passes along all other styles, should be the single file used from other components.
|
||||
- [**`main.ts`**](./../src/presentation/main.ts): Application entry point that mounts and starts Vue application.
|
||||
- [**`electron/`**](./../src/presentation/electron/): Electron configuration for the desktop application.
|
||||
- [**`main.ts`**](./../src/presentation/main.ts): Main process of Electron, started as first thing when app starts.
|
||||
- [**`/public/`**](./../public/): Contains static assets that are directly copied and do not go through webpack.
|
||||
- [**`/vue.config.cjs`**](./../vue.config.cjs): Global Vue CLI configurations loaded by `@vue/cli-service`.
|
||||
- [**`/postcss.config.cjs`**](./../postcss.config.cjs): PostCSS configurations used by Vue CLI internally.
|
||||
- [**`/babel.config.cjs`**](./../babel.config.cjs): Babel configurations for polyfills used by `@vue/cli-plugin-babel`.
|
||||
- [`/src/` **`presentation/`**](./../src/presentation/): Contains Vue and Electron code.
|
||||
- [**`bootstrapping/`**](./../src/presentation/bootstrapping/): Registers Vue components and plugins.
|
||||
- [**`components/`**](./../src/presentation/components/): Contains Vue components and helpers.
|
||||
- [**`Shared/`**](./../src/presentation/components/Shared): Contains shared Vue components and helpers.
|
||||
- [**`hooks`**](../src/presentation/components/Shared/Hooks): Hooks used by components through [dependency injection](#dependency-injections).
|
||||
- [**`/public/`**](../src/presentation/public/): Contains static assets.
|
||||
- [**`assets/`**](./../src/presentation/assets/styles/): Contains assets processed by Vite.
|
||||
- [**`fonts/`**](./../src/presentation/assets/fonts/): Contains fonts.
|
||||
- [**`styles/`**](./../src/presentation/assets/styles/): Contains shared styles.
|
||||
- [**`components/`**](./../src/presentation/assets/styles/components): Contains styles for Vue components.
|
||||
- [**`vendors-extensions/`**](./../src/presentation/assets/styles/third-party-extensions): Contains styles for third-party components.
|
||||
- [**`main.scss`**](./../src/presentation/assets/styles/main.scss): Main Sass file, imported by other components as single entrypoint.
|
||||
- [**`main.ts`**](./../src/presentation/main.ts): Starts Vue app.
|
||||
- [**`electron/`**](./../src/presentation/electron/): Contains Electron code.
|
||||
- [**`main.ts`**](./../src/presentation/main.ts): Starts Electron app.
|
||||
- [**`/vite.config.ts`**](./../vite.config.ts): Contains Vite configurations for building web application.
|
||||
- [**`/postcss.config.cjs`**](./../postcss.config.cjs): Contains PostCSS configurations for Vite.
|
||||
|
||||
## Visual design best-practices
|
||||
|
||||
@@ -86,6 +85,10 @@ Shared components include:
|
||||
- [ModalDialog.vue](./../src/presentation/components/Shared/Modal/ModalDialog.vue) is utilized for rendering modal windows.
|
||||
- [TooltipWrapper.vue](./../src/presentation/components/Shared/TooltipWrapper.vue) acts as a wrapper for rendering tooltips.
|
||||
|
||||
## Desktop builds
|
||||
|
||||
Desktop builds uses `electron-vite` to bundle the code, and `electron-builder` to build and publish the packages.
|
||||
|
||||
## Sass naming convention
|
||||
|
||||
- Use lowercase for variables/functions/mixins, e.g.:
|
||||
|
||||
@@ -60,9 +60,10 @@ These checks validate various qualities like runtime execution, building process
|
||||
|
||||
- [`package.json`](./../package.json): Defines test commands and includes tools used in tests.
|
||||
- [`vite.config.ts`](./../vite.config.ts): Configures `vitest` for unit and integration tests.
|
||||
- [`./src/`](./../src/): Contains the source code subject to testing.
|
||||
- **[`./tests/bootstrap/setup.ts`](./../tests/bootstrap/setup.ts)**: Initializes tests.
|
||||
- **[`./tests/unit/`](./../tests/unit/)**
|
||||
- [`./src/`](./../src/): Contains the code subject to testing.
|
||||
- [`./tests/shared/`](./../tests/shared/): Contains code shared by different test categories.
|
||||
- [`bootstrap/setup.ts`](./../tests/shared/bootstrap/setup.ts): Initializes unit and integration tests.
|
||||
- [`./tests/unit/`](./../tests/unit/)
|
||||
- Stores unit test code.
|
||||
- The directory structure mirrors [`./src/`](./../src).
|
||||
- E.g., tests for [`./src/application/ApplicationFactory.ts`](./../src/application/ApplicationFactory.ts) reside in [`./tests/unit/application/ApplicationFactory.spec.ts`](./../tests/unit/application/ApplicationFactory.spec.ts).
|
||||
@@ -73,8 +74,8 @@ These checks validate various qualities like runtime execution, building process
|
||||
- Shared test cases.
|
||||
- Functions that calls `it()` from [Vitest](https://vitest.dev/) should have `it` prefix.
|
||||
- [`Stubs/`](./../tests/unit/shared/Stubs): Maintains stubs for component isolation, equipped with basic functionalities and, when necessary, spying or mocking capabilities.
|
||||
- **[`./tests/integration/`](./../tests/integration/)**: Contains integration test files.
|
||||
- **[`./tests/e2e/`](./../tests/e2e/)**
|
||||
- [`./tests/integration/`](./../tests/integration/): Contains integration test files.
|
||||
- [`./tests/e2e/`](./../tests/e2e/)
|
||||
- [`cypress.config.ts`](./../cypress.config.ts): Cypress configuration file.
|
||||
- [`./tests/e2e/`](./../tests/e2e/): Base Cypress folder.
|
||||
- [`/specs/`](./../tests/e2e/specs/): Test files named with `.spec.js` extension.
|
||||
|
||||
@@ -4,9 +4,6 @@ This folder contains image files and other resources related to images.
|
||||
|
||||
## logo.svg
|
||||
|
||||
[logo.svg](./logo.svg) is the master logo from which all other icons or images are created from.
|
||||
It should be the only file that will be changed manually.
|
||||
|
||||
[`logo-update.mjs`](./logo-update.mjs) script in this folder updates all the logo files.
|
||||
It should be executed everytime the logo is changed.
|
||||
It automates recreation of logo files in different formats.
|
||||
[`logo.svg`](./logo.svg) serves as the primary logo from which all other icons and images are derived.
|
||||
Only modify this file manually.
|
||||
After making changes, execute `npm run build:icons` to regenerate logo files in various formats.
|
||||
|
||||
3296
package-lock.json
generated
3296
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
27
package.json
27
package.json
@@ -7,13 +7,14 @@
|
||||
"author": "undergroundwires",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"test:unit": "vitest run --dir tests/unit --environment jsdom",
|
||||
"test:integration": "vitest run --dir tests/integration --environment node",
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc --noEmit && vite build",
|
||||
"preview": "vite preview",
|
||||
"test:unit": "vitest run --dir tests/unit",
|
||||
"test:integration": "vitest run --dir tests/integration",
|
||||
"test:e2e": "vue-cli-service test:e2e",
|
||||
"lint": "npm run lint:md && npm run lint:md:consistency && npm run lint:md:relative-urls && npm run lint:eslint && npm run lint:yaml",
|
||||
"create-icons": "node img/logo-update.mjs",
|
||||
"icons:build": "node scripts/logo-update.js",
|
||||
"electron:build": "vue-cli-service electron:build",
|
||||
"electron:serve": "vue-cli-service electron:serve",
|
||||
"lint:eslint": "eslint .",
|
||||
@@ -33,7 +34,6 @@
|
||||
"@fortawesome/vue-fontawesome": "^2.0.9",
|
||||
"@juggle/resize-observer": "^3.4.0",
|
||||
"ace-builds": "^1.23.4",
|
||||
"core-js": "^3.32.0",
|
||||
"cross-fetch": "^4.0.0",
|
||||
"electron-progressbar": "^2.1.0",
|
||||
"file-saver": "^2.0.5",
|
||||
@@ -51,14 +51,13 @@
|
||||
"@types/file-saver": "^2.0.5",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
"@typescript-eslint/parser": "^5.62.0",
|
||||
"@vitejs/plugin-legacy": "^4.1.1",
|
||||
"@vitejs/plugin-vue2": "^2.2.0",
|
||||
"@vue/cli-plugin-babel": "~5.0.8",
|
||||
"@vue/cli-plugin-e2e-cypress": "~5.0.8",
|
||||
"@vue/cli-plugin-typescript": "~5.0.8",
|
||||
"@vue/cli-service": "~5.0.8",
|
||||
"@vue/cli-plugin-e2e-cypress": "^5.0.8",
|
||||
"@vue/eslint-config-airbnb-with-typescript": "^7.0.0",
|
||||
"@vue/eslint-config-typescript": "^11.0.3",
|
||||
"@vue/test-utils": "^1.3.6",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"cypress": "^12.17.2",
|
||||
"electron": "^25.3.2",
|
||||
"electron-builder": "^24.6.3",
|
||||
@@ -66,26 +65,27 @@
|
||||
"electron-icon-builder": "^2.0.1",
|
||||
"electron-log": "^4.4.8",
|
||||
"electron-updater": "^6.1.4",
|
||||
"electron-vite": "^1.0.27",
|
||||
"eslint": "^8.46.0",
|
||||
"eslint-plugin-vue": "^9.6.0",
|
||||
"eslint-plugin-vuejs-accessibility": "^1.2.0",
|
||||
"icon-gen": "^3.0.1",
|
||||
"js-yaml-loader": "^1.2.2",
|
||||
"jsdom": "^22.1.0",
|
||||
"markdownlint-cli": "^0.35.0",
|
||||
"postcss": "^8.4.28",
|
||||
"remark-cli": "^11.0.0",
|
||||
"remark-lint-no-dead-urls": "^1.1.0",
|
||||
"remark-preset-lint-consistent": "^5.1.2",
|
||||
"remark-validate-links": "^12.1.1",
|
||||
"sass": "^1.64.1",
|
||||
"sass-loader": "^13.3.2",
|
||||
"svgexport": "^0.4.2",
|
||||
"ts-loader": "^9.4.4",
|
||||
"terser": "^5.19.2",
|
||||
"tslib": "~2.4.0",
|
||||
"typescript": "~4.6.2",
|
||||
"vite": "^4.4.9",
|
||||
"vitest": "^0.34.2",
|
||||
"vue-cli-plugin-electron-builder": "^3.0.0-alpha.4",
|
||||
"vue-tsc": "^1.8.8",
|
||||
"yaml-lint": "^1.7.0"
|
||||
},
|
||||
"overrides": {
|
||||
@@ -94,6 +94,7 @@
|
||||
}
|
||||
},
|
||||
"//devDependencies": {
|
||||
"terser": "Used by @vitejs/plugin-legacy for minification",
|
||||
"typescript": [
|
||||
"Cannot upgrade to 5.X.X due to unmaintained @vue/cli-plugin-typescript, https://github.com/vuejs/vue-cli/issues/7401",
|
||||
"Cannot upgrade to > 4.6.X otherwise unit tests do not work, https://github.com/evanw/node-source-map-support/issues/252"
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {},
|
||||
},
|
||||
const autoprefixer = require('autoprefixer');
|
||||
|
||||
module.exports = () => {
|
||||
return {
|
||||
plugins: [
|
||||
autoprefixer(),
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ class Paths {
|
||||
constructor(selfDirectory) {
|
||||
const projectRoot = resolve(selfDirectory, '../');
|
||||
this.sourceImage = join(projectRoot, 'img/logo.svg');
|
||||
this.publicDirectory = join(projectRoot, 'public');
|
||||
this.publicDirectory = join(projectRoot, 'src/presentation/public');
|
||||
this.electronBuildDirectory = join(projectRoot, 'build');
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ async function updateDesktopIcons(sourceImage, electronIconsDir) {
|
||||
await ensureFolderExists(electronIconsDir);
|
||||
const temporaryDir = await mkdtemp('icon-');
|
||||
const temporaryPngFile = join(temporaryDir, 'icon.png');
|
||||
console.log(`Converting from SVG (${sourceImage}) to PNG: ${temporaryPngFile}`) // required by icon-builder
|
||||
console.log(`Converting from SVG (${sourceImage}) to PNG: ${temporaryPngFile}`); // required by `icon-builder`
|
||||
await runCommand(
|
||||
'npx',
|
||||
'svgexport',
|
||||
@@ -7,15 +7,17 @@ import MacOsData from '@/application/collections/macos.yaml';
|
||||
import LinuxData from '@/application/collections/linux.yaml';
|
||||
import { parseProjectInformation } from '@/application/Parser/ProjectInformationParser';
|
||||
import { Application } from '@/domain/Application';
|
||||
import { IAppMetadata } from '@/infrastructure/Metadata/IAppMetadata';
|
||||
import { ViteAppMetadata } from '@/infrastructure/Metadata/Vite/ViteAppMetadata';
|
||||
import { parseCategoryCollection } from './CategoryCollectionParser';
|
||||
|
||||
export function parseApplication(
|
||||
parser: CategoryCollectionParserType = parseCategoryCollection,
|
||||
processEnv: NodeJS.ProcessEnv = process.env,
|
||||
parser = parseCategoryCollection,
|
||||
metadata: IAppMetadata = new ViteAppMetadata(),
|
||||
collectionsData = PreParsedCollections,
|
||||
): IApplication {
|
||||
validateCollectionsData(collectionsData);
|
||||
const information = parseProjectInformation(processEnv);
|
||||
const information = parseProjectInformation(metadata);
|
||||
const collections = collectionsData.map((collection) => parser(collection, information));
|
||||
const app = new Application(information, collections);
|
||||
return app;
|
||||
|
||||
@@ -1,28 +1,19 @@
|
||||
import { IProjectInformation } from '@/domain/IProjectInformation';
|
||||
import { ProjectInformation } from '@/domain/ProjectInformation';
|
||||
import { IAppMetadata } from '@/infrastructure/Metadata/IAppMetadata';
|
||||
import { Version } from '@/domain/Version';
|
||||
|
||||
export function parseProjectInformation(
|
||||
environment: NodeJS.ProcessEnv | VueAppEnvironment,
|
||||
metadata: IAppMetadata,
|
||||
): IProjectInformation {
|
||||
const version = new Version(environment[VueAppEnvironmentKeys.VUE_APP_VERSION]);
|
||||
const version = new Version(
|
||||
metadata.version,
|
||||
);
|
||||
return new ProjectInformation(
|
||||
environment[VueAppEnvironmentKeys.VUE_APP_NAME],
|
||||
metadata.name,
|
||||
version,
|
||||
environment[VueAppEnvironmentKeys.VUE_APP_SLOGAN],
|
||||
environment[VueAppEnvironmentKeys.VUE_APP_REPOSITORY_URL],
|
||||
environment[VueAppEnvironmentKeys.VUE_APP_HOMEPAGE_URL],
|
||||
metadata.slogan,
|
||||
metadata.repositoryUrl,
|
||||
metadata.homepageUrl,
|
||||
);
|
||||
}
|
||||
|
||||
export const VueAppEnvironmentKeys = {
|
||||
VUE_APP_VERSION: 'VUE_APP_VERSION',
|
||||
VUE_APP_NAME: 'VUE_APP_NAME',
|
||||
VUE_APP_SLOGAN: 'VUE_APP_SLOGAN',
|
||||
VUE_APP_REPOSITORY_URL: 'VUE_APP_REPOSITORY_URL',
|
||||
VUE_APP_HOMEPAGE_URL: 'VUE_APP_HOMEPAGE_URL',
|
||||
} as const;
|
||||
|
||||
export type VueAppEnvironment = {
|
||||
[K in keyof typeof VueAppEnvironmentKeys]: string;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
// eslint-disable-next-line camelcase
|
||||
import child_process from 'child_process';
|
||||
import { Environment } from '@/application/Environment/Environment';
|
||||
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||
|
||||
13
src/infrastructure/Metadata/IAppMetadata.ts
Normal file
13
src/infrastructure/Metadata/IAppMetadata.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Represents essential metadata about the application.
|
||||
*
|
||||
* Designed to decouple the process of retrieving metadata
|
||||
* (e.g., from the build environment) from the rest of the application.
|
||||
*/
|
||||
export interface IAppMetadata {
|
||||
readonly version: string;
|
||||
readonly name: string;
|
||||
readonly slogan: string;
|
||||
readonly repositoryUrl: string;
|
||||
readonly homepageUrl: string;
|
||||
}
|
||||
29
src/infrastructure/Metadata/Vite/ViteAppMetadata.ts
Normal file
29
src/infrastructure/Metadata/Vite/ViteAppMetadata.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { IAppMetadata } from '../IAppMetadata';
|
||||
|
||||
/**
|
||||
* Provides the application's metadata using Vite's environment variables.
|
||||
*/
|
||||
export class ViteAppMetadata implements IAppMetadata {
|
||||
// Ensure the use of import.meta.env prefix for the following properties.
|
||||
// Vue will replace these statically during production builds.
|
||||
|
||||
public get version(): string {
|
||||
return import.meta.env.VITE_APP_VERSION;
|
||||
}
|
||||
|
||||
public get name(): string {
|
||||
return import.meta.env.VITE_APP_NAME;
|
||||
}
|
||||
|
||||
public get slogan(): string {
|
||||
return import.meta.env.VITE_APP_SLOGAN;
|
||||
}
|
||||
|
||||
public get repositoryUrl(): string {
|
||||
return import.meta.env.VITE_APP_REPOSITORY_URL;
|
||||
}
|
||||
|
||||
public get homepageUrl(): string {
|
||||
return import.meta.env.VITE_APP_HOMEPAGE_URL;
|
||||
}
|
||||
}
|
||||
8
src/infrastructure/Metadata/Vite/ViteEnvironmentKeys.ts
Normal file
8
src/infrastructure/Metadata/Vite/ViteEnvironmentKeys.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
// Only variables prefixed with VITE_ are exposed to Vite-processed code
|
||||
export const VITE_ENVIRONMENT_KEYS = {
|
||||
VERSION: 'VITE_APP_VERSION',
|
||||
NAME: 'VITE_APP_NAME',
|
||||
SLOGAN: 'VITE_APP_SLOGAN',
|
||||
REPOSITORY_URL: 'VITE_APP_REPOSITORY_URL',
|
||||
HOMEPAGE_URL: 'VITE_APP_HOMEPAGE_URL',
|
||||
} as const;
|
||||
11
src/infrastructure/Metadata/Vite/vite-env.d.ts
vendored
Normal file
11
src/infrastructure/Metadata/Vite/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
import { VITE_ENVIRONMENT_KEYS } from './ViteEnvironmentKeys';
|
||||
|
||||
export type ViteEnvironmentVariables = {
|
||||
readonly [K in keyof typeof VITE_ENVIRONMENT_KEYS]: string;
|
||||
};
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ViteEnvironmentVariables
|
||||
}
|
||||
3
src/presentation/README.md
Normal file
3
src/presentation/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# presentation
|
||||
|
||||
See [`presentation.md`](./../../docs/presentation.md)
|
||||
@@ -1,17 +1,19 @@
|
||||
// https://google-webfonts-helper.herokuapp.com/fonts
|
||||
|
||||
@use "@/presentation/assets/styles/vite-path" as *;
|
||||
|
||||
/* slabo-27px-regular - latin-ext_latin */
|
||||
@font-face {
|
||||
font-family: 'Slabo 27px';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('~@/presentation/assets/fonts/slabo-27px-v6-latin-ext_latin-regular.eot'); /* IE9 Compat Modes */
|
||||
src: url('#{$base-assets-path}/fonts/slabo-27px-v6-latin-ext_latin-regular.eot'); /* IE9 Compat Modes */
|
||||
src: local('Slabo 27px'), local('Slabo27px-Regular'),
|
||||
url('~@/presentation/assets/fonts/slabo-27px-v6-latin-ext_latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('~@/presentation/assets/fonts/slabo-27px-v6-latin-ext_latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('~@/presentation/assets/fonts/slabo-27px-v6-latin-ext_latin-regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('~@/presentation/assets/fonts/slabo-27px-v6-latin-ext_latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
|
||||
url('~@/presentation/assets/fonts/slabo-27px-v6-latin-ext_latin-regular.svg#Slabo27px') format('svg'); /* Legacy iOS */
|
||||
url('#{$base-assets-path}/fonts/slabo-27px-v6-latin-ext_latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('#{$base-assets-path}/fonts/slabo-27px-v6-latin-ext_latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('#{$base-assets-path}/fonts/slabo-27px-v6-latin-ext_latin-regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('#{$base-assets-path}/fonts/slabo-27px-v6-latin-ext_latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
|
||||
url('#{$base-assets-path}/fonts/slabo-27px-v6-latin-ext_latin-regular.svg#Slabo27px') format('svg'); /* Legacy iOS */
|
||||
}
|
||||
|
||||
/* yesteryear-regular - latin */
|
||||
@@ -19,13 +21,13 @@
|
||||
font-family: 'Yesteryear';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('~@/presentation/assets/fonts/yesteryear-v8-latin-regular.eot'); /* IE9 Compat Modes */
|
||||
src: url('#{$base-assets-path}/fonts/yesteryear-v8-latin-regular.eot'); /* IE9 Compat Modes */
|
||||
src: local('Yesteryear'), local('Yesteryear-Regular'),
|
||||
url('~@/presentation/assets/fonts/yesteryear-v8-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('~@/presentation/assets/fonts/yesteryear-v8-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('~@/presentation/assets/fonts/yesteryear-v8-latin-regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('~@/presentation/assets/fonts/yesteryear-v8-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
|
||||
url('~@/presentation/assets/fonts/yesteryear-v8-latin-regular.svg#Yesteryear') format('svg'); /* Legacy iOS */
|
||||
url('#{$base-assets-path}/fonts/yesteryear-v8-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('#{$base-assets-path}/fonts/yesteryear-v8-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('#{$base-assets-path}/fonts/yesteryear-v8-latin-regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('#{$base-assets-path}/fonts/yesteryear-v8-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
|
||||
url('#{$base-assets-path}/fonts/yesteryear-v8-latin-regular.svg#Yesteryear') format('svg'); /* Legacy iOS */
|
||||
}
|
||||
|
||||
$font-normal : 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
@use "@/presentation/assets/styles/colors" as *;
|
||||
@use "@/presentation/assets/styles/fonts" as *;
|
||||
@use "@/presentation/assets/styles/mixins" as *;
|
||||
@use "@/presentation/assets/styles/vite-path" as *;
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
|
||||
4
src/presentation/assets/styles/_vite-path.scss
Normal file
4
src/presentation/assets/styles/_vite-path.scss
Normal file
@@ -0,0 +1,4 @@
|
||||
// Define paths specific to Vite's resolution system.
|
||||
// Vite uses the "@" symbol to resolve its aliases for styles.
|
||||
|
||||
$base-assets-path: "@/presentation/assets/";
|
||||
@@ -1,8 +1,8 @@
|
||||
import ace from 'ace-builds';
|
||||
|
||||
/*
|
||||
Following is here because `import 'ace-builds/webpack-resolver';` does not work with webpack 5.
|
||||
Related issue: https://github.com/ajaxorg/ace-builds/issues/211, PR: https://github.com/ajaxorg/ace-builds/pull/221
|
||||
Following is here because `import 'ace-builds/esm-resolver' imports all unused functionality
|
||||
when built with Vite (`npm run build`).
|
||||
*/
|
||||
|
||||
import 'ace-builds/src-noconflict/theme-github';
|
||||
|
||||
@@ -69,6 +69,8 @@ declare module 'liquor-tree' {
|
||||
matcher(query: string, node: ILiquorTreeExistingNode): boolean;
|
||||
}
|
||||
|
||||
const LiquorTree: PluginObject<Vue>;
|
||||
interface LiquorTreeVueComponent extends PluginObject<Vue> {
|
||||
install(Vue: VueConstructor<Vue>, options?: unknown);
|
||||
}
|
||||
export default LiquorTree;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ $text-size: 0.75em; // Lower looks bad on Firefox
|
||||
Use mask element instead of content/background-image etc.
|
||||
This way we can apply current font color to it to match the theme
|
||||
*/
|
||||
mask: url(~@/presentation/assets/icons/external-link.svg) no-repeat 50% 50%;
|
||||
mask: url(@/presentation/assets/icons/external-link.svg) no-repeat 50% 50%;
|
||||
mask-size: cover;
|
||||
content: '';
|
||||
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
@node:unchecked="nodeSelected($event)"
|
||||
ref="liquorTree"
|
||||
>
|
||||
<span class="tree-text" slot-scope="{ node }">
|
||||
<NodeContent :data="convertExistingToNode(node)" />
|
||||
</span>
|
||||
<template v-slot:default="{ node }">
|
||||
<span class="tree-text">
|
||||
<NodeContent :data="convertExistingToNode(node)" />
|
||||
</span>
|
||||
</template>
|
||||
</LiquorTree>
|
||||
</span>
|
||||
<span v-else>Nooo 😢</span>
|
||||
@@ -192,4 +194,3 @@ async function tryUntilDefined<T>(
|
||||
return value;
|
||||
}
|
||||
</script>
|
||||
./Node/INodeContent
|
||||
|
||||
@@ -7,6 +7,7 @@ import fetch from 'cross-fetch';
|
||||
import { ProjectInformation } from '@/domain/ProjectInformation';
|
||||
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||
import { Version } from '@/domain/Version';
|
||||
import { ViteAppMetadata } from '@/infrastructure/Metadata/Vite/ViteAppMetadata';
|
||||
import { parseProjectInformation } from '@/application/Parser/ProjectInformationParser';
|
||||
import { UpdateProgressBar } from './UpdateProgressBar';
|
||||
|
||||
@@ -28,7 +29,7 @@ export async function handleManualUpdate(info: UpdateInfo) {
|
||||
}
|
||||
|
||||
function getTargetProject(targetVersion: string) {
|
||||
const existingProject = parseProjectInformation(process.env);
|
||||
const existingProject = parseProjectInformation(new ViteAppMetadata());
|
||||
const targetProject = new ProjectInformation(
|
||||
existingProject.name,
|
||||
new Version(targetVersion),
|
||||
|
||||
38
src/presentation/index.html
Normal file
38
src/presentation/index.html
Normal file
@@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>Privacy is sexy 🍑🍆 - Enforce privacy & security on Windows, macOS and Linux</title>
|
||||
<meta name="robots" content="index,follow" />
|
||||
<meta name="description"
|
||||
content="Web tool to generate scripts for enforcing privacy & security best-practices such as stopping data collection of Windows and different softwares on it." />
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
<style>
|
||||
#javascriptDisabled {
|
||||
background: #eceef1;
|
||||
margin: 5rem auto;
|
||||
max-width: 800px;
|
||||
font-size: 7px;
|
||||
padding: 3rem;
|
||||
border: 1px solid#333a45;
|
||||
font-size: 1.5rem;
|
||||
line-height: 150%;
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
|
||||
}
|
||||
</style>
|
||||
<div id="javascriptDisabled">
|
||||
<h1>Problem loading page</h1>
|
||||
<p>The page does not work without JavaScript enabled. Please enable it to use privacy.sexy. There's no shady stuff
|
||||
as 100% of the website is open source.</p>
|
||||
</div>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,16 +1,10 @@
|
||||
import Vue from 'vue';
|
||||
import { buildContext } from '@/application/Context/ApplicationContextFactory';
|
||||
import App from './components/App.vue';
|
||||
import { ApplicationBootstrapper } from './bootstrapping/ApplicationBootstrapper';
|
||||
|
||||
buildContext().then(() => {
|
||||
// hack workaround to solve running tests through
|
||||
// Vue CLI throws 'Top-level-await is only supported in EcmaScript Modules'
|
||||
// once migrated to vite, remove buildContext() call from here and use top-level-await
|
||||
new ApplicationBootstrapper()
|
||||
.bootstrap(Vue);
|
||||
new ApplicationBootstrapper()
|
||||
.bootstrap(Vue);
|
||||
|
||||
new Vue({
|
||||
render: (h) => h(App),
|
||||
}).$mount('#app');
|
||||
});
|
||||
new Vue({
|
||||
render: (h) => h(App),
|
||||
}).$mount('#app');
|
||||
|
||||
|
Before Width: | Height: | Size: 353 KiB After Width: | Height: | Size: 353 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@@ -1,13 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>Privacy is sexy 🍑🍆 - Enforce privacy & security on Windows, macOS and Linux</title>
|
||||
<meta name="robots" content="index,follow" />
|
||||
<meta name="description" content="Web tool to generate scripts for enforcing privacy & security best-practices such as stopping data collection of Windows and different softwares on it."/>
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
<style>
|
||||
@@ -28,7 +19,5 @@
|
||||
<p>The page does not work without JavaScript enabled. Please enable it to use privacy.sexy. There's no shady stuff as 100% of the website is open source.</p>
|
||||
</div>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,47 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ViteAppMetadata } from '@/infrastructure/Metadata/Vite/ViteAppMetadata';
|
||||
import packageJson from '@/../package.json';
|
||||
import { PropertyKeys } from '@tests/shared/TypeHelpers';
|
||||
|
||||
describe('ViteAppMetadata', () => {
|
||||
describe('populates from package.json', () => {
|
||||
interface ITestCase {
|
||||
readonly getActualValue: (sut: ViteAppMetadata) => string;
|
||||
readonly expected: string;
|
||||
}
|
||||
const testCases: { readonly [K in PropertyKeys<ViteAppMetadata>]: ITestCase } = {
|
||||
name: {
|
||||
expected: packageJson.name,
|
||||
getActualValue: (sut) => sut.name,
|
||||
},
|
||||
version: {
|
||||
expected: packageJson.version,
|
||||
getActualValue: (sut) => sut.version,
|
||||
},
|
||||
slogan: {
|
||||
expected: packageJson.slogan,
|
||||
getActualValue: (sut) => sut.slogan,
|
||||
},
|
||||
repositoryUrl: {
|
||||
expected: packageJson.repository.url,
|
||||
getActualValue: (sut) => sut.repositoryUrl,
|
||||
},
|
||||
homepageUrl: {
|
||||
expected: packageJson.homepage,
|
||||
getActualValue: (sut) => sut.homepageUrl,
|
||||
},
|
||||
};
|
||||
Object.entries(testCases).forEach(([propertyName, { expected, getActualValue }]) => {
|
||||
it(`should correctly get the value of ${propertyName}`, () => {
|
||||
// arrange
|
||||
const sut = new ViteAppMetadata();
|
||||
|
||||
// act
|
||||
const actualValue = getActualValue(sut);
|
||||
|
||||
// assert
|
||||
expect(actualValue).toBe(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
8
tests/shared/TypeHelpers.ts
Normal file
8
tests/shared/TypeHelpers.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export type Constructible<T, TArgs extends unknown[] = never> = {
|
||||
prototype: T;
|
||||
apply: (this: unknown, args: TArgs) => void;
|
||||
};
|
||||
|
||||
export type PropertyKeys<T> = {
|
||||
[K in keyof T]: T[K] extends (...args: unknown[]) => unknown ? never : K;
|
||||
}[keyof T];
|
||||
@@ -1,8 +1,9 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import type { CollectionData } from '@/application/collections/';
|
||||
import { VueAppEnvironment, parseProjectInformation } from '@/application/Parser/ProjectInformationParser';
|
||||
import { parseProjectInformation } from '@/application/Parser/ProjectInformationParser';
|
||||
import { CategoryCollectionParserType, parseApplication } from '@/application/Parser/ApplicationParser';
|
||||
import { IAppMetadata } from '@/infrastructure/Metadata/IAppMetadata';
|
||||
import WindowsData from '@/application/collections/windows.yaml';
|
||||
import MacOsData from '@/application/collections/macos.yaml';
|
||||
import LinuxData from '@/application/collections/linux.yaml';
|
||||
@@ -12,9 +13,9 @@ import { ICategoryCollection } from '@/domain/ICategoryCollection';
|
||||
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||
import { getEnumValues } from '@/application/Common/Enum';
|
||||
import { CategoryCollectionStub } from '@tests/unit/shared/Stubs/CategoryCollectionStub';
|
||||
import { getProcessEnvironmentStub } from '@tests/unit/shared/Stubs/ProcessEnvironmentStub';
|
||||
import { CollectionDataStub } from '@tests/unit/shared/Stubs/CollectionDataStub';
|
||||
import { getAbsentCollectionTestCases, AbsentObjectTestCases } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
import { AppMetadataStub } from '@tests/unit/shared/Stubs/AppMetadataStub';
|
||||
|
||||
describe('ApplicationParser', () => {
|
||||
describe('parseApplication', () => {
|
||||
@@ -41,7 +42,7 @@ describe('ApplicationParser', () => {
|
||||
describe('processEnv', () => {
|
||||
it('used to parse expected project information', () => {
|
||||
// arrange
|
||||
const env = getProcessEnvironmentStub();
|
||||
const env = new AppMetadataStub();
|
||||
const expected = parseProjectInformation(env);
|
||||
const parserSpy = new CategoryCollectionParserSpy();
|
||||
const parserMock = parserSpy.mockParser();
|
||||
@@ -138,7 +139,7 @@ class ApplicationParserBuilder {
|
||||
private categoryCollectionParser: CategoryCollectionParserType = new CategoryCollectionParserSpy()
|
||||
.mockParser();
|
||||
|
||||
private environment: VueAppEnvironment = getProcessEnvironmentStub();
|
||||
private environment: IAppMetadata = new AppMetadataStub();
|
||||
|
||||
private collectionsData: CollectionData[] = [new CollectionDataStub()];
|
||||
|
||||
@@ -150,7 +151,7 @@ class ApplicationParserBuilder {
|
||||
}
|
||||
|
||||
public withEnvironment(
|
||||
environment: VueAppEnvironment,
|
||||
environment: IAppMetadata,
|
||||
): this {
|
||||
this.environment = environment;
|
||||
return this;
|
||||
|
||||
@@ -1,59 +1,59 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { VueAppEnvironmentKeys, parseProjectInformation } from '@/application/Parser/ProjectInformationParser';
|
||||
import { getProcessEnvironmentStub } from '@tests/unit/shared/Stubs/ProcessEnvironmentStub';
|
||||
import { parseProjectInformation } from '@/application/Parser/ProjectInformationParser';
|
||||
import { IProjectInformation } from '@/domain/IProjectInformation';
|
||||
import { AppMetadataStub } from '@tests/unit/shared/Stubs/AppMetadataStub';
|
||||
|
||||
describe('ProjectInformationParser', () => {
|
||||
describe('parseProjectInformation', () => {
|
||||
interface IEnvironmentParsingTestCase {
|
||||
readonly testCaseName: string;
|
||||
readonly environmentVariableName: string;
|
||||
readonly environmentVariableValue: string;
|
||||
readonly setMetadata: (appMetadataStub: AppMetadataStub, value: string) => AppMetadataStub;
|
||||
readonly expectedValue: string;
|
||||
readonly getActualValue: (info: IProjectInformation) => string;
|
||||
}
|
||||
const testCases: readonly IEnvironmentParsingTestCase[] = [
|
||||
{
|
||||
testCaseName: 'version',
|
||||
environmentVariableName: VueAppEnvironmentKeys.VUE_APP_VERSION,
|
||||
environmentVariableValue: '0.11.3',
|
||||
setMetadata: (metadata, value) => metadata.withVersion(value),
|
||||
expectedValue: '0.11.3',
|
||||
getActualValue: (info) => info.version.toString(),
|
||||
},
|
||||
{
|
||||
testCaseName: 'name',
|
||||
environmentVariableName: VueAppEnvironmentKeys.VUE_APP_NAME,
|
||||
environmentVariableValue: 'expected-app-name',
|
||||
setMetadata: (metadata, value) => metadata.witName(value),
|
||||
expectedValue: 'expected-app-name',
|
||||
getActualValue: (info) => info.name,
|
||||
},
|
||||
{
|
||||
testCaseName: 'homepage',
|
||||
environmentVariableName: VueAppEnvironmentKeys.VUE_APP_HOMEPAGE_URL,
|
||||
environmentVariableValue: 'https://expected.sexy',
|
||||
setMetadata: (metadata, value) => metadata.withHomepageUrl(value),
|
||||
expectedValue: 'https://expected.sexy',
|
||||
getActualValue: (info) => info.homepage,
|
||||
},
|
||||
{
|
||||
testCaseName: 'repositoryUrl',
|
||||
environmentVariableName: VueAppEnvironmentKeys.VUE_APP_REPOSITORY_URL,
|
||||
environmentVariableValue: 'https://expected-repository.url',
|
||||
setMetadata: (metadata, value) => metadata.withRepositoryUrl(value),
|
||||
expectedValue: 'https://expected-repository.url',
|
||||
getActualValue: (info) => info.repositoryUrl,
|
||||
},
|
||||
{
|
||||
testCaseName: 'slogan',
|
||||
environmentVariableName: VueAppEnvironmentKeys.VUE_APP_SLOGAN,
|
||||
environmentVariableValue: 'expected-slogan',
|
||||
setMetadata: (metadata, value) => metadata.withSlogan(value),
|
||||
expectedValue: 'expected-slogan',
|
||||
getActualValue: (info) => info.slogan,
|
||||
},
|
||||
];
|
||||
for (const testCase of testCases) {
|
||||
it(`${testCase.testCaseName}`, () => {
|
||||
for (const {
|
||||
expectedValue, testCaseName, setMetadata, getActualValue,
|
||||
} of testCases) {
|
||||
it(testCaseName, () => {
|
||||
// act
|
||||
const expected = testCase.environmentVariableValue;
|
||||
const env = getProcessEnvironmentStub();
|
||||
env[testCase.environmentVariableName] = testCase.environmentVariableValue;
|
||||
const metadata = setMetadata(new AppMetadataStub(), expectedValue);
|
||||
// act
|
||||
const info = parseProjectInformation(env);
|
||||
const info = parseProjectInformation(metadata);
|
||||
// assert
|
||||
const actual = testCase.getActualValue(info);
|
||||
expect(actual).to.be.equal(expected);
|
||||
const actual = getActualValue(info);
|
||||
expect(actual).to.be.equal(expectedValue);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,11 +4,12 @@ import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||
import { EnumRangeTestRunner } from '@tests/unit/application/Common/EnumRangeTestRunner';
|
||||
import { VersionStub } from '@tests/unit/shared/Stubs/VersionStub';
|
||||
import { Version } from '@/domain/Version';
|
||||
import { PropertyKeys } from '@tests/shared/TypeHelpers';
|
||||
|
||||
describe('ProjectInformation', () => {
|
||||
describe('retrieval of property values', () => {
|
||||
interface IPropertyTestCase {
|
||||
readonly testCaseName: string;
|
||||
interface IInformationParsingTestCase {
|
||||
readonly description?: string;
|
||||
readonly expectedValue: string;
|
||||
readonly buildWithExpectedValue: (
|
||||
builder: ProjectInformationBuilder,
|
||||
@@ -16,81 +17,105 @@ describe('ProjectInformation', () => {
|
||||
) => ProjectInformationBuilder;
|
||||
readonly getActualValue: (sut: ProjectInformation) => string;
|
||||
}
|
||||
const propertyTestCases: readonly IPropertyTestCase[] = [
|
||||
{
|
||||
testCaseName: 'name',
|
||||
expectedValue: 'expected-name',
|
||||
const propertyTestCases: {
|
||||
readonly [K in PropertyKeys<ProjectInformation>]: readonly IInformationParsingTestCase[];
|
||||
} = {
|
||||
name: [{
|
||||
expectedValue: 'expected-app-name',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withName(expected),
|
||||
getActualValue: (sut) => sut.name,
|
||||
},
|
||||
{
|
||||
testCaseName: 'version',
|
||||
}],
|
||||
version: [{
|
||||
expectedValue: '0.11.3',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withVersion(new VersionStub(expected)),
|
||||
getActualValue: (sut) => sut.version.toString(),
|
||||
},
|
||||
{
|
||||
testCaseName: 'repositoryWebUrl - not ending with .git',
|
||||
expectedValue: 'expected-repository-url',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withRepositoryUrl(expected),
|
||||
getActualValue: (sut) => sut.repositoryWebUrl,
|
||||
},
|
||||
{
|
||||
testCaseName: 'repositoryWebUrl - ending with .git',
|
||||
expectedValue: 'expected-repository-url',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withRepositoryUrl(`${expected}.git`),
|
||||
getActualValue: (sut) => sut.repositoryWebUrl,
|
||||
},
|
||||
{
|
||||
testCaseName: 'slogan',
|
||||
}],
|
||||
slogan: [{
|
||||
expectedValue: 'expected-slogan',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withSlogan(expected),
|
||||
getActualValue: (sut) => sut.slogan,
|
||||
},
|
||||
{
|
||||
testCaseName: 'homepage',
|
||||
}],
|
||||
repositoryUrl: [{
|
||||
description: 'without `.git` suffix',
|
||||
expectedValue: 'expected-repository-url',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withRepositoryUrl(expected),
|
||||
getActualValue: (sut) => sut.repositoryUrl,
|
||||
}, {
|
||||
description: 'with `.git` suffix',
|
||||
expectedValue: 'expected-repository-url',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withRepositoryUrl(expected),
|
||||
getActualValue: (sut) => sut.repositoryUrl,
|
||||
}],
|
||||
repositoryWebUrl: [{
|
||||
description: 'without `.git` suffix',
|
||||
expectedValue: 'expected-repository-url',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withRepositoryUrl(expected),
|
||||
getActualValue: (sut) => sut.repositoryWebUrl,
|
||||
}, {
|
||||
description: 'with `.git` suffix',
|
||||
expectedValue: 'expected-repository-url',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withRepositoryUrl(`${expected}.git`),
|
||||
getActualValue: (sut) => sut.repositoryWebUrl,
|
||||
}],
|
||||
homepage: [{
|
||||
expectedValue: 'expected-homepage',
|
||||
buildWithExpectedValue: (builder, expected) => builder
|
||||
.withHomepage(expected),
|
||||
getActualValue: (sut) => sut.homepage,
|
||||
},
|
||||
{
|
||||
testCaseName: 'feedbackUrl',
|
||||
}],
|
||||
feedbackUrl: [{
|
||||
description: 'without `.git` suffix',
|
||||
expectedValue: 'https://github.com/undergroundwires/privacy.sexy/issues',
|
||||
buildWithExpectedValue: (builder) => builder
|
||||
.withRepositoryUrl('https://github.com/undergroundwires/privacy.sexy'),
|
||||
getActualValue: (sut) => sut.feedbackUrl,
|
||||
}, {
|
||||
description: 'with `.git` suffix',
|
||||
expectedValue: 'https://github.com/undergroundwires/privacy.sexy/issues',
|
||||
buildWithExpectedValue: (builder) => builder
|
||||
.withRepositoryUrl('https://github.com/undergroundwires/privacy.sexy.git'),
|
||||
getActualValue: (sut) => sut.feedbackUrl,
|
||||
},
|
||||
{
|
||||
testCaseName: 'releaseUrl',
|
||||
}],
|
||||
releaseUrl: [{
|
||||
description: 'without `.git` suffix',
|
||||
expectedValue: 'https://github.com/undergroundwires/privacy.sexy/releases/tag/0.7.2',
|
||||
buildWithExpectedValue: (builder) => builder
|
||||
.withRepositoryUrl('https://github.com/undergroundwires/privacy.sexy')
|
||||
.withVersion(new VersionStub('0.7.2')),
|
||||
getActualValue: (sut) => sut.releaseUrl,
|
||||
}, {
|
||||
description: 'with `.git` suffix',
|
||||
expectedValue: 'https://github.com/undergroundwires/privacy.sexy/releases/tag/0.7.2',
|
||||
buildWithExpectedValue: (builder) => builder
|
||||
.withRepositoryUrl('https://github.com/undergroundwires/privacy.sexy.git')
|
||||
.withVersion(new VersionStub('0.7.2')),
|
||||
getActualValue: (sut) => sut.releaseUrl,
|
||||
},
|
||||
];
|
||||
for (const testCase of propertyTestCases) {
|
||||
it(`should return the expected ${testCase.testCaseName} value`, () => {
|
||||
// arrange
|
||||
const expected = testCase.expectedValue;
|
||||
const builder = new ProjectInformationBuilder();
|
||||
const sut = testCase
|
||||
.buildWithExpectedValue(builder, expected)
|
||||
.build();
|
||||
}],
|
||||
};
|
||||
Object.entries(propertyTestCases).forEach(([propertyName, testList]) => {
|
||||
testList.forEach(({
|
||||
description, buildWithExpectedValue, expectedValue, getActualValue,
|
||||
}) => {
|
||||
it(`${propertyName}${description ? ` (${description})` : ''}`, () => {
|
||||
// arrange
|
||||
const builder = new ProjectInformationBuilder();
|
||||
const sut = buildWithExpectedValue(builder, expectedValue).build();
|
||||
|
||||
// act
|
||||
const actual = testCase.getActualValue(sut);
|
||||
// act
|
||||
const actual = getActualValue(sut);
|
||||
|
||||
// assert
|
||||
expect(actual).to.equal(expected);
|
||||
// assert
|
||||
expect(actual).to.equal(expectedValue);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
describe('correct retrieval of download URL per operating system', () => {
|
||||
const testCases: ReadonlyArray<{
|
||||
@@ -128,7 +153,7 @@ describe('ProjectInformation', () => {
|
||||
.withVersion(new VersionStub(version))
|
||||
.withRepositoryUrl(repositoryUrl)
|
||||
.build();
|
||||
// act
|
||||
// act
|
||||
const actual = sut.getDownloadUrl(os);
|
||||
// assert
|
||||
expect(actual).to.equal(expected);
|
||||
|
||||
65
tests/unit/infrastructure/Metadata/ViteAppMetadata.spec.ts
Normal file
65
tests/unit/infrastructure/Metadata/ViteAppMetadata.spec.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
describe, beforeEach, afterEach, expect,
|
||||
} from 'vitest';
|
||||
import { ViteAppMetadata } from '@/infrastructure/Metadata/Vite/ViteAppMetadata';
|
||||
import { VITE_ENVIRONMENT_KEYS } from '@/infrastructure/Metadata/Vite/ViteEnvironmentKeys';
|
||||
import { PropertyKeys } from '@tests/shared/TypeHelpers';
|
||||
|
||||
describe('ViteAppMetadata', () => {
|
||||
describe('reads values from import.meta.env', () => {
|
||||
let originalMetaEnv;
|
||||
beforeEach(() => {
|
||||
originalMetaEnv = { ...import.meta.env };
|
||||
});
|
||||
afterEach(() => {
|
||||
Object.assign(import.meta.env, originalMetaEnv);
|
||||
});
|
||||
|
||||
interface ITestCase {
|
||||
readonly getActualValue: (sut: ViteAppMetadata) => string;
|
||||
readonly environmentVariable: typeof VITE_ENVIRONMENT_KEYS[
|
||||
keyof typeof VITE_ENVIRONMENT_KEYS];
|
||||
readonly expected: string;
|
||||
}
|
||||
const testCases: { [K in PropertyKeys<ViteAppMetadata>]: ITestCase } = {
|
||||
name: {
|
||||
environmentVariable: VITE_ENVIRONMENT_KEYS.NAME,
|
||||
expected: 'expected-name',
|
||||
getActualValue: (sut) => sut.name,
|
||||
},
|
||||
version: {
|
||||
environmentVariable: VITE_ENVIRONMENT_KEYS.VERSION,
|
||||
expected: 'expected-version',
|
||||
getActualValue: (sut) => sut.version,
|
||||
},
|
||||
repositoryUrl: {
|
||||
environmentVariable: VITE_ENVIRONMENT_KEYS.REPOSITORY_URL,
|
||||
expected: 'expected-slogan',
|
||||
getActualValue: (sut) => sut.repositoryUrl,
|
||||
},
|
||||
slogan: {
|
||||
environmentVariable: VITE_ENVIRONMENT_KEYS.SLOGAN,
|
||||
expected: 'expected-repositoryUrl',
|
||||
getActualValue: (sut) => sut.slogan,
|
||||
},
|
||||
homepageUrl: {
|
||||
environmentVariable: VITE_ENVIRONMENT_KEYS.HOMEPAGE_URL,
|
||||
expected: 'expected-homepageUrl',
|
||||
getActualValue: (sut) => sut.homepageUrl,
|
||||
},
|
||||
};
|
||||
Object.values(testCases).forEach(({ environmentVariable, expected, getActualValue }) => {
|
||||
it(`should correctly get the value of ${environmentVariable}`, () => {
|
||||
// arrange
|
||||
import.meta.env[environmentVariable] = expected;
|
||||
|
||||
// act
|
||||
const sut = new ViteAppMetadata();
|
||||
const actualValue = getActualValue(sut);
|
||||
|
||||
// assert
|
||||
expect(actualValue).toBe(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import { expect, describe, it } from 'vitest';
|
||||
import { VITE_ENVIRONMENT_KEYS } from '@/infrastructure/Metadata/Vite/ViteEnvironmentKeys';
|
||||
|
||||
describe('VITE_ENVIRONMENT_KEYS', () => {
|
||||
describe('each key should have a non-empty string', () => {
|
||||
Object.entries(VITE_ENVIRONMENT_KEYS).forEach(([key, value]) => {
|
||||
it(`The key ${key} should have a non-empty string value`, () => {
|
||||
expect(typeof value).toBe('string');
|
||||
expect(value.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
38
tests/unit/shared/Stubs/AppMetadataStub.ts
Normal file
38
tests/unit/shared/Stubs/AppMetadataStub.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { IAppMetadata } from '@/infrastructure/Metadata/IAppMetadata';
|
||||
|
||||
export class AppMetadataStub implements IAppMetadata {
|
||||
public version = '0.12.2';
|
||||
|
||||
public name = 'stub-name';
|
||||
|
||||
public slogan = 'stub-slogan';
|
||||
|
||||
public repositoryUrl = 'stub-repository-url';
|
||||
|
||||
public homepageUrl = 'stub-homepage-url';
|
||||
|
||||
public withVersion(version: string): this {
|
||||
this.version = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
public witName(name: string): this {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withSlogan(slogan: string): this {
|
||||
this.slogan = slogan;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withRepositoryUrl(repositoryUrl: string): this {
|
||||
this.repositoryUrl = repositoryUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withHomepageUrl(homepageUrl: string): this {
|
||||
this.homepageUrl = homepageUrl;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { expect } from 'vitest';
|
||||
import { Constructible } from '@tests/shared/TypeHelpers';
|
||||
import { ICodeValidationRule } from '@/application/Parser/Script/Validation/ICodeValidationRule';
|
||||
import { ICodeValidator } from '@/application/Parser/Script/Validation/ICodeValidator';
|
||||
import { Type } from '../Type';
|
||||
|
||||
export class CodeValidatorStub implements ICodeValidator {
|
||||
public callHistory = new Array<{
|
||||
@@ -21,7 +21,7 @@ export class CodeValidatorStub implements ICodeValidator {
|
||||
|
||||
public assertHistory(expected: {
|
||||
validatedCodes: readonly string[],
|
||||
rules: readonly Type<ICodeValidationRule>[],
|
||||
rules: readonly Constructible<ICodeValidationRule>[],
|
||||
}) {
|
||||
expect(this.callHistory).to.have.lengthOf(expected.validatedCodes.length);
|
||||
const actualValidatedCodes = this.callHistory.map((args) => args.code);
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { VueAppEnvironment } from '@/application/Parser/ProjectInformationParser';
|
||||
|
||||
export function getProcessEnvironmentStub(): VueAppEnvironment {
|
||||
return {
|
||||
VUE_APP_VERSION: '0.11.3',
|
||||
VUE_APP_NAME: 'stub-name',
|
||||
VUE_APP_SLOGAN: 'stub-slogan',
|
||||
VUE_APP_REPOSITORY_URL: 'stub-repository-url',
|
||||
VUE_APP_HOMEPAGE_URL: 'stub-homepage-url',
|
||||
};
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { it, expect } from 'vitest';
|
||||
import { Type } from '../Type';
|
||||
import { Constructible } from '@tests/shared/TypeHelpers';
|
||||
|
||||
interface ISingletonTestData<T> {
|
||||
getter: () => T;
|
||||
expectedType: Type<T>;
|
||||
expectedType: Constructible<T>;
|
||||
}
|
||||
|
||||
export function itIsSingleton<T>(test: ISingletonTestData<T>): void {
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export type Type<T, TArgs extends unknown[] = never> = Function & {
|
||||
prototype: T,
|
||||
apply: (this: unknown, args: TArgs) => void
|
||||
};
|
||||
@@ -1,26 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2017",
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
],
|
||||
"target": "ES2017",
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||
"module": "esnext",
|
||||
"jsx": "preserve",
|
||||
"importHelpers": true,
|
||||
"downlevelIteration": true,
|
||||
"moduleResolution": "node",
|
||||
"jsx": "preserve",
|
||||
"moduleResolution": "Node",
|
||||
"experimentalDecorators": true,
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"noUnusedLocals": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"types": [
|
||||
"webpack-env"
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { resolve } from 'path';
|
||||
import { VITE_ENVIRONMENT_KEYS } from './src/infrastructure/Metadata/Vite/ViteEnvironmentKeys';
|
||||
import tsconfigJson from './tsconfig.json';
|
||||
import packageJson from './package.json';
|
||||
|
||||
export function getAliasesFromTsConfig(): Record<string, string> {
|
||||
const { paths } = tsconfigJson.compilerOptions;
|
||||
@@ -12,3 +14,22 @@ export function getAliasesFromTsConfig(): Record<string, string> {
|
||||
return aliases;
|
||||
}, {});
|
||||
}
|
||||
|
||||
type ViteEnvironmentKeyValues = {
|
||||
[K in typeof VITE_ENVIRONMENT_KEYS[keyof typeof VITE_ENVIRONMENT_KEYS]]: string
|
||||
};
|
||||
|
||||
export function getClientEnvironmentVariables(): Record<string, string> {
|
||||
const environmentVariables: ViteEnvironmentKeyValues = {
|
||||
[VITE_ENVIRONMENT_KEYS.NAME]: packageJson.name,
|
||||
[VITE_ENVIRONMENT_KEYS.VERSION]: packageJson.version,
|
||||
[VITE_ENVIRONMENT_KEYS.REPOSITORY_URL]: packageJson.repository.url,
|
||||
[VITE_ENVIRONMENT_KEYS.HOMEPAGE_URL]: packageJson.homepage,
|
||||
[VITE_ENVIRONMENT_KEYS.SLOGAN]: packageJson.slogan,
|
||||
};
|
||||
return Object.entries(environmentVariables).reduce((acc, [key, value]) => {
|
||||
const newKey = `import.meta.env.${key}`;
|
||||
const newValue = JSON.stringify(value);
|
||||
return { ...acc, [newKey]: newValue };
|
||||
}, {});
|
||||
}
|
||||
|
||||
@@ -1,21 +1,54 @@
|
||||
/// <reference types="vitest" />
|
||||
import { resolve } from 'path';
|
||||
import { defineConfig } from 'vite';
|
||||
import Vue2 from '@vitejs/plugin-vue2';
|
||||
import legacy from '@vitejs/plugin-legacy';
|
||||
import vue from '@vitejs/plugin-vue2';
|
||||
import ViteYaml from '@modyfi/vite-plugin-yaml';
|
||||
import { getAliasesFromTsConfig } from './vite-config-helper';
|
||||
import { getAliasesFromTsConfig, getClientEnvironmentVariables } from './vite-config-helper';
|
||||
|
||||
const WEB_DIRECTORY = resolve(__dirname, 'src/presentation');
|
||||
const TEST_INITIALIZATION_FILE = resolve(__dirname, 'tests/shared/bootstrap/setup.ts');
|
||||
const NODE_CORE_MODULES = ['os', 'child_process', 'fs', 'path'];
|
||||
|
||||
export default defineConfig({
|
||||
root: WEB_DIRECTORY,
|
||||
plugins: [
|
||||
Vue2(),
|
||||
vue(),
|
||||
ViteYaml(),
|
||||
legacy(),
|
||||
],
|
||||
esbuild: {
|
||||
supported: {
|
||||
'top-level-await': true, // Exclude browsers not supporting top-level-await
|
||||
},
|
||||
},
|
||||
define: {
|
||||
...getClientEnvironmentVariables(),
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
...getAliasesFromTsConfig(),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
rollupOptions: {
|
||||
// Ensure Node core modules are externalized and don't trigger warnings in browser builds
|
||||
external: {
|
||||
...NODE_CORE_MODULES,
|
||||
},
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 3169,
|
||||
},
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
alias: {
|
||||
...getAliasesFromTsConfig(),
|
||||
},
|
||||
setupFiles: [
|
||||
'tests/bootstrap/setup.ts',
|
||||
TEST_INITIALIZATION_FILE,
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/* Keeping here until Vitest migration */
|
||||
|
||||
const { resolve } = require('path');
|
||||
const { defineConfig } = require('@vue/cli-service');
|
||||
const packageJson = require('./package.json');
|
||||
const tsconfigJson = require('./tsconfig.json');
|
||||
|
||||
loadVueAppRuntimeVariables();
|
||||
fixTestBuildWithModules();
|
||||
|
||||
module.exports = defineConfig({
|
||||
transpileDependencies: true,
|
||||
@@ -29,32 +30,6 @@ module.exports = defineConfig({
|
||||
// log stacks like `console.log(new Error().stack)`
|
||||
devtool: 'eval-source-map',
|
||||
},
|
||||
pluginOptions: {
|
||||
// https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/guide.html#native-modules
|
||||
electronBuilder: {
|
||||
mainProcessFile: './src/presentation/electron/main.ts', // https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/configuration.html#webpack-configuration
|
||||
nodeIntegration: true, // required to reach Node.js APIs for environment specific logic
|
||||
// https://www.electron.build/configuration/configuration
|
||||
builderOptions: {
|
||||
publish: [{
|
||||
// https://www.electron.build/configuration/publish#githuboptions
|
||||
// https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/recipes.html#enable-publishing-to-github
|
||||
provider: 'github',
|
||||
vPrefixedTagName: false, // default: true
|
||||
releaseType: 'release', // or "draft" (default), "prerelease"
|
||||
}],
|
||||
mac: { // https://www.electron.build/configuration/mac
|
||||
target: 'dmg',
|
||||
},
|
||||
win: { // https://www.electron.build/configuration/win
|
||||
target: 'nsis',
|
||||
},
|
||||
linux: { // https://www.electron.build/configuration/linux
|
||||
target: 'AppImage',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
function addWebpackRule(name, test, loader, config) {
|
||||
@@ -96,15 +71,3 @@ function getAliasesFromTsConfig() {
|
||||
return aliases;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function fixTestBuildWithModules() {
|
||||
/*
|
||||
Workaround for Vue CLI issue during tests breaks projects that rely on ES6 modules and mocha.
|
||||
Setting VUE_CLI_TEST to true prevents the Vue CLI from altering the module transpilation.
|
||||
This fix ensures `npm run build -- --mode test` works successfully.
|
||||
See: https://github.com/vuejs/vue-cli/issues/7417
|
||||
*/
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
process.env.VUE_CLI_TEST = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user