From 2851a5144f6145069e0324905e4910b0118911b6 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 22 Nov 2023 01:51:12 +0100 Subject: [PATCH 1/4] clean structure --- .eslintrc.json | 5 ++++- .storybook/preview.ts | 6 ++---- README.md | 1 - package.json | 13 +++++++++++- renderer/_default.page.client.ts | 6 +++--- renderer/_default.page.server.ts | 10 +++++---- renderer/app.ts | 21 ++++++++++--------- renderer/{ => context}/usePageContext.ts | 8 +++---- renderer/{ => plugins}/i18n.ts | 6 ++---- renderer/plugins/pinia.ts | 3 +++ renderer/{ => plugins}/vuetify.ts | 0 {tests => scripts/tests}/mock.$t.ts | 0 {tests => scripts/tests}/plugin.vuetify.ts | 6 ++---- .../index => components}/ClickCounter.test.ts | 0 .../index => components}/ClickCounter.vue | 0 {renderer => src/components}/PageShell.vue | 0 {renderer => src/components}/VikeLink.vue | 2 +- {renderer => src/components}/logo.svg | 0 src/pages/index/index.page.vue | 2 +- tsconfig.json | 11 +++++++++- types/Page.ts | 5 +++++ renderer/types.ts => types/PageContext.ts | 18 ++++++---------- types/PageProps.ts | 3 +++ {src => types}/vue.d.ts | 0 vite.config.ts | 13 ++++++++++++ 25 files changed, 88 insertions(+), 51 deletions(-) rename renderer/{ => context}/usePageContext.ts (92%) rename renderer/{ => plugins}/i18n.ts (60%) create mode 100644 renderer/plugins/pinia.ts rename renderer/{ => plugins}/vuetify.ts (100%) rename {tests => scripts/tests}/mock.$t.ts (100%) rename {tests => scripts/tests}/plugin.vuetify.ts (51%) rename src/{pages/index => components}/ClickCounter.test.ts (100%) rename src/{pages/index => components}/ClickCounter.vue (100%) rename {renderer => src/components}/PageShell.vue (100%) rename {renderer => src/components}/VikeLink.vue (82%) rename {renderer => src/components}/logo.svg (100%) create mode 100644 types/Page.ts rename renderer/types.ts => types/PageContext.ts (57%) create mode 100644 types/PageProps.ts rename {src => types}/vue.d.ts (100%) diff --git a/.eslintrc.json b/.eslintrc.json index 485bb1d..847ccc3 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -70,7 +70,10 @@ "import/no-dynamic-require": "error", "import/no-internal-modules": "off", "import/no-relative-packages": "error", - "import/no-relative-parent-imports": "error", + "import/no-relative-parent-imports": [ + "error", + { "ignore": ["#[src,root,components,pages,plugins,context,types]/*"] } + ], "import/no-self-import": "error", "import/no-unresolved": "error", "import/no-useless-path-segments": "error", diff --git a/.storybook/preview.ts b/.storybook/preview.ts index ee63b23..66cbf53 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -1,10 +1,8 @@ import { setup } from '@storybook/vue3' import { createPinia } from 'pinia' -// eslint-disable-next-line import/no-relative-parent-imports -import i18n from '../renderer/i18n' -// eslint-disable-next-line import/no-relative-parent-imports -import CreateVuetify from '../renderer/vuetify' +import i18n from '#plugins/i18n' +import CreateVuetify from '#plugins/vuetify' import { withVuetifyTheme } from './withVuetifyTheme.decorator' diff --git a/README.md b/README.md index 0aaf255..fa12e5e 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,6 @@ The following endpoints are provided given the right command is executed or all - [ ] figma - [ ] chromatic -- [ ] github actions - [ ] feature zähler -> pinia tore ## Known Problems diff --git a/package.json b/package.json index 6aa994a..0ef222d 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,9 @@ "docker", "remark-cli" ], - "author": "Ulf Gebhardt", + "author": { + "name": "Ulf Gebhardt" + }, "license": "Apache-2.0", "bugs": { "url": "https://github.com/IT4Change/boilerplate-frontend/issues" @@ -122,5 +124,14 @@ "stylelint-config-standard-scss": "^11.1.0", "vitest": "^0.34.6", "vuepress": "^2.0.0-rc.0" + }, + "imports": { + "#root/*": "./*", + "#src/*": "./src/*", + "#components/*": "./src/components/*", + "#pages/*": "./src/pages/*", + "#plugins/*": "./renderer/plugins/*", + "#context/*": "./renderer/context/*", + "#types/*": "./types/*" } } diff --git a/renderer/_default.page.client.ts b/renderer/_default.page.client.ts index 0104d10..53796fc 100644 --- a/renderer/_default.page.client.ts +++ b/renderer/_default.page.client.ts @@ -1,8 +1,6 @@ import { createApp } from './app' -import type { PageContextClient } from './types' - -export { render } +import type { PageContextClient } from '#types/PageContext' // This render() hook only supports SSR, see https://vike.dev/render-modes for how to modify render() to support SPA async function render(pageContext: PageContextClient) { @@ -15,3 +13,5 @@ async function render(pageContext: PageContextClient) { /* To enable Client-side Routing: export const clientRouting = true // !! WARNING !! Before doing so, read https://vike.dev/clientRouting */ + +export { render } diff --git a/renderer/_default.page.server.ts b/renderer/_default.page.server.ts index 6b2f872..dee8e86 100644 --- a/renderer/_default.page.server.ts +++ b/renderer/_default.page.server.ts @@ -1,13 +1,13 @@ import { renderToString as renderToString_ } from '@vue/server-renderer' import { escapeInject, dangerouslySkipEscape } from 'vike/server' -import { createApp } from './app' -import logoUrl from './logo.svg' +import logoUrl from '#components/logo.svg' -import type { PageContextServer } from './types' +import { createApp } from './app' + +import type { PageContextServer } from '#types/PageContext' import type { App } from 'vue' -export { render } // See https://vike.dev/data-fetching export const passToClient = ['pageProps', 'urlPathname'] @@ -56,3 +56,5 @@ async function renderToString(app: App) { if (err) throw err return appHtml } + +export { render } diff --git a/renderer/app.ts b/renderer/app.ts index 71afa40..90c69ef 100644 --- a/renderer/app.ts +++ b/renderer/app.ts @@ -1,16 +1,16 @@ -import { createPinia } from 'pinia' import { createSSRApp, defineComponent, h } from 'vue' -import i18n from './i18n' -import PageShell from './PageShell.vue' -import { setPageContext } from './usePageContext' -import CreateVuetify from './vuetify' +import PageShell from '#components//PageShell.vue' +import { setPageContext } from '#context/usePageContext' +import i18n from '#plugins/i18n' +import pinia from '#plugins/pinia' +import CreateVuetify from '#plugins/vuetify' +import { Page } from '#types/Page' +import { PageProps } from '#types/PageProps' -import type { Component, PageContext, PageProps } from './types' +import type { PageContext } from '#types/PageContext' -export { createApp } - -function createApp(Page: Component, pageProps: PageProps | undefined, pageContext: PageContext) { +function createApp(Page: Page, pageProps: PageProps | undefined, pageContext: PageContext) { const PageWithLayout = defineComponent({ render() { return h( @@ -25,7 +25,6 @@ function createApp(Page: Component, pageProps: PageProps | undefined, pageContex }, }) - const pinia = createPinia() const app = createSSRApp(PageWithLayout) app.use(pinia) app.use(i18n) @@ -36,3 +35,5 @@ function createApp(Page: Component, pageProps: PageProps | undefined, pageContex return app } + +export { createApp } diff --git a/renderer/usePageContext.ts b/renderer/context/usePageContext.ts similarity index 92% rename from renderer/usePageContext.ts rename to renderer/context/usePageContext.ts index 5970e1a..e7e7163 100644 --- a/renderer/usePageContext.ts +++ b/renderer/context/usePageContext.ts @@ -3,13 +3,10 @@ import { inject } from 'vue' -import { PageContext } from './types' +import { PageContext } from '#types/PageContext' import type { App, InjectionKey } from 'vue' -export { usePageContext } -export { setPageContext } - const key: InjectionKey = Symbol(undefined) function usePageContext() { @@ -21,3 +18,6 @@ function usePageContext() { function setPageContext(app: App, pageContext: PageContext) { app.provide(key, pageContext) } + +export { usePageContext } +export { setPageContext } diff --git a/renderer/i18n.ts b/renderer/plugins/i18n.ts similarity index 60% rename from renderer/i18n.ts rename to renderer/plugins/i18n.ts index bfef1cb..9ed0a5f 100644 --- a/renderer/i18n.ts +++ b/renderer/plugins/i18n.ts @@ -1,10 +1,8 @@ import { createI18n } from 'vue-i18n' -// eslint-disable-next-line import/no-relative-parent-imports -import de from '../src/locales/de.json' +import de from '#src/locales/de.json' // import { de as $vuetify } from 'vuetify/locale' -// eslint-disable-next-line import/no-relative-parent-imports -import en from '../src/locales/en.json' +import en from '#src/locales/en.json' // import { en as $vuetify } from 'vuetify/locale' export default createI18n({ diff --git a/renderer/plugins/pinia.ts b/renderer/plugins/pinia.ts new file mode 100644 index 0000000..f00b209 --- /dev/null +++ b/renderer/plugins/pinia.ts @@ -0,0 +1,3 @@ +import { createPinia } from 'pinia' + +export default createPinia() diff --git a/renderer/vuetify.ts b/renderer/plugins/vuetify.ts similarity index 100% rename from renderer/vuetify.ts rename to renderer/plugins/vuetify.ts diff --git a/tests/mock.$t.ts b/scripts/tests/mock.$t.ts similarity index 100% rename from tests/mock.$t.ts rename to scripts/tests/mock.$t.ts diff --git a/tests/plugin.vuetify.ts b/scripts/tests/plugin.vuetify.ts similarity index 51% rename from tests/plugin.vuetify.ts rename to scripts/tests/plugin.vuetify.ts index c2235c0..3802ffb 100644 --- a/tests/plugin.vuetify.ts +++ b/scripts/tests/plugin.vuetify.ts @@ -1,9 +1,7 @@ import { config } from '@vue/test-utils' -// eslint-disable-next-line import/no-relative-parent-imports -import i18n from '../renderer/i18n' -// eslint-disable-next-line import/no-relative-parent-imports -import vuetify from '../renderer/vuetify' +import i18n from '#plugins/i18n' +import vuetify from '#plugins/vuetify' config.global.plugins.push(vuetify(i18n)) diff --git a/src/pages/index/ClickCounter.test.ts b/src/components/ClickCounter.test.ts similarity index 100% rename from src/pages/index/ClickCounter.test.ts rename to src/components/ClickCounter.test.ts diff --git a/src/pages/index/ClickCounter.vue b/src/components/ClickCounter.vue similarity index 100% rename from src/pages/index/ClickCounter.vue rename to src/components/ClickCounter.vue diff --git a/renderer/PageShell.vue b/src/components/PageShell.vue similarity index 100% rename from renderer/PageShell.vue rename to src/components/PageShell.vue diff --git a/renderer/VikeLink.vue b/src/components/VikeLink.vue similarity index 82% rename from renderer/VikeLink.vue rename to src/components/VikeLink.vue index 7b76a89..f79f032 100644 --- a/renderer/VikeLink.vue +++ b/src/components/VikeLink.vue @@ -4,7 +4,7 @@ diff --git a/renderer/logo.svg b/src/components/logo.svg similarity index 100% rename from renderer/logo.svg rename to src/components/logo.svg diff --git a/src/pages/index/index.page.vue b/src/pages/index/index.page.vue index c99cda2..113e994 100644 --- a/src/pages/index/index.page.vue +++ b/src/pages/index/index.page.vue @@ -8,5 +8,5 @@ diff --git a/tsconfig.json b/tsconfig.json index 59b5d5e..7a2480f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,16 @@ "types": ["vite/client"], "skipLibCheck": true, "esModuleInterop": true, - "resolveJsonModule": true + "resolveJsonModule": true, + "paths": { + "#root/*": ["./*"], + "#src/*": ["./src/*"], + "#components/*": ["./src/components/*"], + "#pages/*": ["./src/pages/*"], + "#plugins/*": ["./renderer/plugins/*"], + "#context/*": ["./renderer/context/*"], + "#types/*": ["./types/*"] + } }, "ts-node": { "transpileOnly": true, diff --git a/types/Page.ts b/types/Page.ts new file mode 100644 index 0000000..b562c67 --- /dev/null +++ b/types/Page.ts @@ -0,0 +1,5 @@ +import type { ComponentPublicInstance } from 'vue' + +type Page = ComponentPublicInstance // https://stackoverflow.com/questions/63985658/how-to-type-vue-instance-out-of-definecomponent-in-vue-3/63986086#63986086 + +export type { Page } diff --git a/renderer/types.ts b/types/PageContext.ts similarity index 57% rename from renderer/types.ts rename to types/PageContext.ts index c4393f5..24a52a1 100644 --- a/renderer/types.ts +++ b/types/PageContext.ts @@ -1,25 +1,19 @@ -import type { ComponentPublicInstance } from 'vue' +import { Page } from '#types/Page' +import { PageProps } from '#types/PageProps' export type { PageContextServer, /* - // When using Client Routing https://vike.dev/clientRouting - PageContextClient, - PageContext, - / */ + // When using Client Routing https://vike.dev/clientRouting + PageContextClient, + PageContext, + / */ // When using Server Routing PageContextClientWithServerRouting as PageContextClient, PageContextWithServerRouting as PageContext, //* / } from 'vike/types' -type PageProps = object -type Component = ComponentPublicInstance // https://stackoverflow.com/questions/63985658/how-to-type-vue-instance-out-of-definecomponent-in-vue-3/63986086#63986086 -type Page = Component - -export type { PageProps } -export type { Component } - // https://vike.dev/pageContext#typescript declare global { // eslint-disable-next-line @typescript-eslint/no-namespace diff --git a/types/PageProps.ts b/types/PageProps.ts new file mode 100644 index 0000000..ef7d982 --- /dev/null +++ b/types/PageProps.ts @@ -0,0 +1,3 @@ +type PageProps = object + +export type { PageProps } diff --git a/src/vue.d.ts b/types/vue.d.ts similarity index 100% rename from src/vue.d.ts rename to types/vue.d.ts diff --git a/vite.config.ts b/vite.config.ts index 7d3cda6..340f674 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,3 +1,5 @@ +import path from 'path' + import vueI18n from '@intlify/unplugin-vue-i18n/vite' import vue from '@vitejs/plugin-vue' import vike from 'vike/plugin' @@ -18,6 +20,17 @@ const config: UserConfig = { outDir: './build', }, ssr: { noExternal: ['vuetify'] }, + resolve: { + alias: { + '#root': __dirname, + '#src': path.join(__dirname, '/src'), + '#components': path.join(__dirname, '/src/components'), + '#pages': path.join(__dirname, '/src/pages'), + '#plugins': path.join(__dirname, '/renderer/plugins'), + '#context': path.join(__dirname, '/renderer/context'), + '#types': path.join(__dirname, '/types'), + }, + }, } export default config From 5c0d220276286f7b43a8e1b98c5ac3b7ae280e37 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 22 Nov 2023 01:51:41 +0100 Subject: [PATCH 2/4] vitest adjustments --- vitest.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vitest.config.ts b/vitest.config.ts index 7e2029a..6c30bd9 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -8,13 +8,13 @@ export default mergeConfig( test: { globals: true, environment: 'happy-dom', - setupFiles: ['tests/mock.$t.ts', 'tests/plugin.vuetify.ts'], + setupFiles: ['scripts/tests/mock.$t.ts', 'scripts/tests/plugin.vuetify.ts'], coverage: { all: true, include: ['src/**/*.{js,jsx,ts,tsx,vue}'], lines: 2, functions: 0, - branches: 10, + branches: 8, statements: 2, // 100: true, }, From 8a37ac2b4d5fb085183375d19184091829f44f75 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 22 Nov 2023 02:15:23 +0100 Subject: [PATCH 3/4] assets folder and alias --- .eslintrc.json | 2 +- package.json | 1 + renderer/_default.page.server.ts | 2 +- {public => src/assets}/favicon.ico | Bin .../it4c-logo2-clean-bg_alpha-128x128.png | Bin 0 -> 14581 bytes src/components/PageShell.vue | 4 +- src/components/logo.svg | 36 ------------------ tsconfig.json | 1 + vite.config.ts | 1 + 9 files changed, 8 insertions(+), 39 deletions(-) rename {public => src/assets}/favicon.ico (100%) create mode 100644 src/assets/it4c-logo2-clean-bg_alpha-128x128.png delete mode 100644 src/components/logo.svg diff --git a/.eslintrc.json b/.eslintrc.json index 847ccc3..9c19f4c 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -72,7 +72,7 @@ "import/no-relative-packages": "error", "import/no-relative-parent-imports": [ "error", - { "ignore": ["#[src,root,components,pages,plugins,context,types]/*"] } + { "ignore": ["#[src,root,components,pages,assets,plugins,context,types]/*"] } ], "import/no-self-import": "error", "import/no-unresolved": "error", diff --git a/package.json b/package.json index 0ef222d..56df7d2 100644 --- a/package.json +++ b/package.json @@ -130,6 +130,7 @@ "#src/*": "./src/*", "#components/*": "./src/components/*", "#pages/*": "./src/pages/*", + "#assets/*": "./src/assets/*", "#plugins/*": "./renderer/plugins/*", "#context/*": "./renderer/context/*", "#types/*": "./types/*" diff --git a/renderer/_default.page.server.ts b/renderer/_default.page.server.ts index dee8e86..680ccbb 100644 --- a/renderer/_default.page.server.ts +++ b/renderer/_default.page.server.ts @@ -1,7 +1,7 @@ import { renderToString as renderToString_ } from '@vue/server-renderer' import { escapeInject, dangerouslySkipEscape } from 'vike/server' -import logoUrl from '#components/logo.svg' +import logoUrl from '#assets/favicon.ico' import { createApp } from './app' diff --git a/public/favicon.ico b/src/assets/favicon.ico similarity index 100% rename from public/favicon.ico rename to src/assets/favicon.ico diff --git a/src/assets/it4c-logo2-clean-bg_alpha-128x128.png b/src/assets/it4c-logo2-clean-bg_alpha-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..9626249541985a1a954b609b1a7705514f74f005 GIT binary patch literal 14581 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 E0UpXGZ2$lO literal 0 HcmV?d00001 diff --git a/src/components/PageShell.vue b/src/components/PageShell.vue index 0249d40..25a5adb 100644 --- a/src/components/PageShell.vue +++ b/src/components/PageShell.vue @@ -4,7 +4,7 @@