Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1. Version des Vue.js Frontends #156

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/venv
/.venv
/.idea
.idea
*.iml
config.ini
__pycache__
/dist
/.vscode
.vscode
.DS_Store

/.mypy_cache
/.pytest_cache
Expand All @@ -16,4 +17,5 @@ __pycache__

/example.qpy
/questionpy_sdk/resources/minimal_example.zip
/questionpy_sdk/webserver/question_state_storage/
/questionpy_sdk/webserver_legacy/question_state_storage/
/questionpy_sdk/webserver/static/
17 changes: 17 additions & 0 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
# The QuestionPy SDK is free software released under terms of the MIT license. See LICENSE.md.
# (c) Technische Universität Berlin, innoCampus <[email protected]>

import subprocess
import sys
import zipfile
from pathlib import Path
from typing import Any
Expand All @@ -22,8 +24,23 @@ def create_example_zip() -> None:
zip_file.write(file, file.relative_to(minimal_example), COMPRESS_TYPE)


def _run_command(args: list[str], rel_path: str) -> None:
cwd = Path(__file__).parent.absolute() / rel_path
try:
subprocess.run(args, cwd=cwd, check=True, text=True, stdout=sys.stdout, stderr=sys.stderr) # noqa: S603
except subprocess.CalledProcessError as e:
msg = f"npm build failed with exit code {e.returncode}"
raise RuntimeError(msg) from e


def build_frontend() -> None:
_run_command(["npm", "ci", "--ignore-scripts"], "frontend")
_run_command(["npm", "run", "build"], "frontend")


def build(_setup_kwargs: Any) -> None:
create_example_zip()
build_frontend()


if __name__ == "__main__":
Expand Down
11 changes: 11 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
logs
*.log
npm-debug.log*

node_modules
coverage
*.local

*.tsbuildinfo
/.vite
/components.d.ts
6 changes: 6 additions & 0 deletions frontend/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"singleQuote": true,
"printWidth": 120
}
68 changes: 68 additions & 0 deletions frontend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# QuestionPy SDK (Frontend)

A single-page application (SPA) for the QuestionPy SDK, developed using Vue.js.

## Development Setup

```sh
$ npm install
```

### Compile and Hot-Reload for Development

Start Vite dev server.

```sh
$ npm run dev
```

Run `questionpy-sdk` with reverse-proxying to the Vite development server.

```sh
$ USE_VITE_DEV_SERVER=true questionpy-sdk run examples/minimal
```

Use `VITE_DEV_SERVER` to override the default Vite dev server (`http://localhost:5173`).

### Type-Check, Compile and Minify for Production

```sh
$ npm run build
```

The production build is saved under `questionpy_sdk/webserver/static`.

### Run Tests with [Vitest](https://vitest.dev/)

```sh
$ npm run test
```

### Lint with [ESLint](https://eslint.org/)

```sh
$ npm run lint
```

### Format with [Prettier](https://prettier.io/)

Check if formatting is correct for all files.

```sh
$ npm run format-check
```

Auto-format all files.

```sh
$ npm run format
```

## Type Support for `.vue` Imports in TS

TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) is needed to make the TypeScript language service aware of `.vue` types.

## Icon Set

[Material Design Icons](https://icon-sets.iconify.design/mdi/) licensed under [Apache License
2.0](https://github.com/google/material-design-icons/blob/master/LICENSE).
8 changes: 8 additions & 0 deletions frontend/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/// <reference types="vite/client" />
/// <reference types="unplugin-icons/types/vue" />

// core-js/actual/regexp/escape
// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/8ddda4dc45ff72a23229a3d738239f2c18528117/types/core-js/index.d.ts#L63C1-L65C2
interface RegExpConstructor {
escape(str: string): string
}
70 changes: 70 additions & 0 deletions frontend/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import pluginVitest from '@vitest/eslint-plugin'
import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'
import eslintPluginSimpleImportSort from 'eslint-plugin-simple-import-sort'
import pluginVue from 'eslint-plugin-vue'

const BASE_NAME = 'qpy-frontend'
const groupWithTypes = (/** @type {string} */ re) => [re, `${re}.*\\u0000$`]

const config = defineConfigWithVueTs(
{
name: `${BASE_NAME}/files-to-lint`,
files: ['**/*.{ts,mts,tsx,vue}'],
},

{
name: `${BASE_NAME}/files-to-ignore`,
ignores: ['**/dist/**', '**/.vite/**', 'components.d.ts'],
},

...pluginVue.configs['flat/essential'],
vueTsConfigs.recommended,

{
...pluginVitest.configs.recommended,
files: ['src/**/__tests__/*'],
},

skipFormatting,

{
name: `${BASE_NAME}/sort-imports`,
plugins: {
'simple-import-sort': eslintPluginSimpleImportSort,
},
rules: {
'simple-import-sort/imports': [
'error',
{
// https://github.com/lydell/eslint-plugin-simple-import-sort#custom-grouping
// custom groups with type imports last in each group
groups: [
['^\\u0000'], // side-effects
groupWithTypes('^node:'), // node modules
groupWithTypes('^[@~]?(?:(?!\\/))\\w'), // 3rd party imports
groupWithTypes('^@\\/'), // project imports
['(?<!\\u0000)$'], // absolute imports
groupWithTypes('^\\.'), // relative imports
],
},
],
'simple-import-sort/exports': 'error',
},
},

{
name: `${BASE_NAME}/custom-overrides`,
rules: {
// Allow removing keys by destructuring
'@typescript-eslint/no-unused-vars': [
'error',
{
ignoreRestSiblings: true,
},
],
},
},
)

export default config
13 changes: 13 additions & 0 deletions frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>QuestionPy SDK</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
Loading
Loading