@component-hook/create-app 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +61 -37
  2. package/dist/index.js +39 -22
  3. package/package.json +2 -2
  4. package/template-vue/.browserslistrc +10 -0
  5. package/template-vue/.github/workflows/preview.yml +1 -1
  6. package/template-vue/.husky/commit-msg +0 -2
  7. package/template-vue/.husky/pre-commit +0 -2
  8. package/template-vue/README.md.art +34 -55
  9. package/template-vue/_gitignore +0 -3
  10. package/template-vue/index.html.art +2 -0
  11. package/template-vue/lint-staged.config.js +2 -0
  12. package/template-vue/package.json +32 -38
  13. package/template-vue/playwright.config.ts +12 -23
  14. package/template-vue/postcss.config.js +13 -10
  15. package/template-vue/src/__tests__/e2e/home.spec.ts +61 -0
  16. package/template-vue/src/__tests__/unit/{components/indexPage → pages/home/components}/HelloWorld.test.ts +2 -2
  17. package/template-vue/src/__tests__/unit/pages/home/index.test.ts +17 -0
  18. package/template-vue/src/components/common/index.ts +1 -0
  19. package/template-vue/src/components/common/svg-icon/index.ts +1 -0
  20. package/template-vue/src/main.ts +4 -7
  21. package/template-vue/src/{components/indexPage → pages/home/components}/HelloWorld.vue +3 -8
  22. package/template-vue/src/pages/{IndexPage.vue → home/index.vue} +15 -3
  23. package/template-vue/src/plugins/i18n.ts +2 -6
  24. package/template-vue/src/router/index.ts +2 -2
  25. package/template-vue/src/stores/constants.ts.art +1 -0
  26. package/template-vue/src/stores/index.ts +14 -2
  27. package/template-vue/src/stores/modules/config.ts +1 -1
  28. package/template-vue/src/styles/base.css +48 -0
  29. package/template-vue/src/styles/common/all.css +1 -0
  30. package/template-vue/src/styles/common/button.css +15 -0
  31. package/template-vue/src/styles/index.css +3 -0
  32. package/template-vue/src/styles/tailwind.css +1 -0
  33. package/template-vue/src/vite-env.d.ts +1 -0
  34. package/template-vue/tsconfig.app.json +2 -3
  35. package/template-vue/tsconfig.node.json +2 -2
  36. package/template-vue/tsconfig.vitest.json +5 -3
  37. package/template-vue/vite.config.ts +14 -7
  38. package/template-vue/vitest.config.ts +1 -4
  39. package/template-vue/{src/__tests__/setup/unit-test.ts → vitest.setup.ts} +7 -1
  40. package/template-vue/public/mockServiceWorker.js +0 -307
  41. package/template-vue/src/__tests__/e2e/IndexPage.spec.ts +0 -49
  42. package/template-vue/src/components.d.ts +0 -14
  43. package/template-vue/src/styles/common/all.postcss +0 -1
  44. package/template-vue/src/styles/common/button.postcss +0 -12
  45. package/template-vue/src/styles/index.postcss +0 -1
  46. package/template-vue/src/styles/tailwind.postcss +0 -39
  47. package/template-vue/tailwind.config.js +0 -20
  48. /package/template-vue/src/assets/{images/svgIcons → svg-icons}/vue.svg +0 -0
  49. /package/template-vue/src/components/common/{SvgIcon.vue → svg-icon/src/index.vue} +0 -0
@@ -0,0 +1,61 @@
1
+ import { expect, test } from '@playwright/test';
2
+
3
+ test.beforeEach(async ({ page }) => {
4
+ await page.goto('/');
5
+ });
6
+
7
+ test('click Vite logo open Vite official website blank tab', async ({ page }) => {
8
+ const link = page.getByRole('link', { name: /vite logo/i });
9
+
10
+ await expect(link).toBeVisible();
11
+ const [popup] = await Promise.all([page.waitForEvent('popup'), link.evaluate((node: HTMLElement) => node.click())]);
12
+
13
+ await popup.waitForLoadState();
14
+ await expect(popup).toHaveTitle('Vite | Next Generation Frontend Tooling');
15
+ });
16
+
17
+ test('click Vue logo open Vue official website blank tab', async ({ page }) => {
18
+ const link = page.getByLabel(/vue link/i);
19
+
20
+ await expect(link).toBeVisible();
21
+ const [popup] = await Promise.all([page.waitForEvent('popup'), link.evaluate((node: HTMLElement) => node.click())]);
22
+
23
+ await popup.waitForLoadState();
24
+ await expect(popup).toHaveTitle('Vue.js - The Progressive JavaScript Framework | Vue.js');
25
+ });
26
+
27
+ test('homepage count button interact', async ({ page }) => {
28
+ await page.getByRole('button', { name: 'count is 0' }).click();
29
+ await expect(page.getByRole('button', { name: 'count is 1' })).toBeVisible();
30
+ await page.getByRole('button', { name: 'count is 1' }).click();
31
+ await expect(page.getByRole('button', { name: 'count is 2' })).toBeVisible();
32
+ });
33
+
34
+ test('locale change interact', async ({ page }) => {
35
+ await page.getByRole('button', { name: 'English' }).click();
36
+ await expect(page.getByRole('button', { name: '中文' })).toBeVisible();
37
+ await page.getByRole('button', { name: '中文' }).click();
38
+ await expect(page.getByRole('button', { name: 'English' })).toBeVisible();
39
+ });
40
+
41
+ test('click create-vue link open Vue quick start blank tab', async ({ page }) => {
42
+ const link = page.getByRole('link', { name: 'create-vue' });
43
+
44
+ await expect(link).toBeVisible();
45
+ const [popup] = await Promise.all([page.waitForEvent('popup'), link.evaluate((node: HTMLElement) => node.click())]);
46
+
47
+ await popup.waitForLoadState();
48
+ await expect(popup).toHaveTitle('Quick Start | Vue.js');
49
+ });
50
+
51
+ test('click Volar link open language-tools github blank tab', async ({ page }) => {
52
+ const link = page.getByRole('link', { name: 'Volar' });
53
+
54
+ await expect(link).toBeVisible();
55
+ const [popup] = await Promise.all([page.waitForEvent('popup'), link.evaluate((node: HTMLElement) => node.click())]);
56
+
57
+ await popup.waitForLoadState();
58
+ await expect(popup).toHaveTitle(
59
+ 'GitHub - vuejs/language-tools: ⚡ High-performance Vue language tooling based-on Volar.js',
60
+ );
61
+ });
@@ -1,11 +1,11 @@
1
1
  import userEvent from '@testing-library/user-event';
2
2
  import { screen } from '@testing-library/vue';
3
3
  import { renderComponent } from '@/__tests__/unit/render';
4
- import HelloWorld from '@/components/indexPage/HelloWorld.vue';
4
+ import HelloWorld from '@/pages/home/components/HelloWorld.vue';
5
5
  import i18n from '@/plugins/i18n';
6
6
  import { useConfigStore } from '@/stores';
7
7
 
8
- describe('HelloWorld component', () => {
8
+ describe('home page HelloWorld component', () => {
9
9
  const { t } = i18n.global;
10
10
 
11
11
  it('renders the correct content', () => {
@@ -0,0 +1,17 @@
1
+ import { screen } from '@testing-library/vue';
2
+ import { renderComponent } from '@/__tests__/unit/render';
3
+ import Home from '@/pages/home/index.vue';
4
+
5
+ describe('home page', () => {
6
+ it('renders the correct content', () => {
7
+ renderComponent(Home);
8
+ const viteLink = screen.getByRole('link', { name: /vite logo/i });
9
+ const vueLink = screen.getByLabelText(/vue link/i);
10
+
11
+ expect(viteLink).toHaveAttribute('href', 'https://vitejs.dev');
12
+ expect(viteLink).toHaveAttribute('target', '_blank');
13
+
14
+ expect(vueLink).toHaveAttribute('href', 'https://vuejs.org/');
15
+ expect(vueLink).toHaveAttribute('target', '_blank');
16
+ });
17
+ });
@@ -0,0 +1 @@
1
+ export * from './svg-icon';
@@ -0,0 +1 @@
1
+ export { default as SvgIcon } from './src/index.vue';
@@ -1,24 +1,21 @@
1
- import { createPinia } from 'pinia';
2
- import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
3
1
  import { createApp } from 'vue';
4
2
  import i18NPlugin from '@/plugins/i18n';
5
3
 
6
4
  import router from '@/router';
7
5
  import App from './App.vue';
6
+ import { createPinia } from './stores';
8
7
  import 'virtual:svg-icons-register';
9
- import '@/styles/tailwind.postcss';
10
- import '@/styles/index.postcss';
8
+ import '@/styles/index.css';
11
9
 
12
- if (process.env.NODE_ENV === 'mockServiceWorker') {
10
+ if (import.meta.env.VITE_APP_MOCK === 'service-worker') {
13
11
  const { worker } = await import('@/mocks/browser');
14
12
 
15
13
  worker.start();
16
14
  }
17
15
 
18
- const pinia = createPinia();
19
16
  const app = createApp(App);
17
+ const pinia = createPinia();
20
18
 
21
- pinia.use(piniaPluginPersistedstate);
22
19
  app.use(pinia);
23
20
  app.use(router);
24
21
  app.use(i18NPlugin);
@@ -18,12 +18,7 @@ function changeLocale() {
18
18
  <h1>{{ msg }}</h1>
19
19
 
20
20
  <div class="p-8">
21
- <button
22
- type="button"
23
- @click="count++"
24
- >
25
- count is {{ count }}
26
- </button>
21
+ <button @click="count++">count is {{ count }}</button>
27
22
  </div>
28
23
 
29
24
  <p>
@@ -52,8 +47,8 @@ function changeLocale() {
52
47
  </button>
53
48
  </template>
54
49
 
55
- <style lang="postcss" scoped>
50
+ <style lang="css" scoped>
56
51
  .read-the-docs {
57
- @apply text-[#888];
52
+ color: #888;
58
53
  }
59
54
  </style>
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
- import HelloWorld from '@/components/indexPage/HelloWorld.vue';
2
+ import { SvgIcon } from '@/components/common';
3
+ import HelloWorld from './components/HelloWorld.vue';
3
4
  </script>
4
5
 
5
6
  <template>
@@ -17,6 +18,7 @@ import HelloWorld from '@/components/indexPage/HelloWorld.vue';
17
18
  <a
18
19
  href="https://vuejs.org/"
19
20
  target="_blank"
21
+ aria-label="Vue link"
20
22
  >
21
23
  <svg-icon
22
24
  name="vue"
@@ -24,11 +26,21 @@ import HelloWorld from '@/components/indexPage/HelloWorld.vue';
24
26
  />
25
27
  </a>
26
28
  </div>
29
+
27
30
  <hello-world msg="Vite + Vue" />
28
31
  </template>
29
32
 
30
- <style lang="postcss" scoped>
33
+ <style lang="css" scoped>
31
34
  .logo {
32
- @apply w-24 h-24 p-6 mx-auto will-change-[filter] transition-[filter] duration-300 hover:drop-shadow-[0_0_2em_#646cffaa];
35
+ width: 96px;
36
+ height: 96px;
37
+ margin: 0 auto;
38
+ padding: 24px;
39
+ will-change: filter;
40
+ transition: filter 300ms;
41
+
42
+ &:hover {
43
+ filter: drop-shadow(0 0 2em #646cffaa);
44
+ }
33
45
  }
34
46
  </style>
@@ -1,15 +1,11 @@
1
+ import messages from '@intlify/unplugin-vue-i18n/messages';
1
2
  import { createI18n } from 'vue-i18n';
2
- import enUS from '@/locales/en-US.json';
3
- import zhTW from '@/locales/zh-TW.json';
4
3
 
5
4
  const i18n = createI18n({
6
5
  legacy: import.meta.env.MODE === 'test',
7
6
  locale: navigator.language,
8
7
  fallbackLocale: 'en-US',
9
- messages: {
10
- 'zh-TW': zhTW,
11
- 'en-US': enUS,
12
- },
8
+ messages,
13
9
  });
14
10
 
15
11
  export default i18n;
@@ -1,5 +1,5 @@
1
1
  import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router';
2
- import IndexPage from '@/pages/IndexPage.vue';
2
+ import HomePage from '@/pages/home/index.vue';
3
3
 
4
4
  export const routes: Array<RouteRecordRaw> = [
5
5
  {
@@ -8,7 +8,7 @@ export const routes: Array<RouteRecordRaw> = [
8
8
  },
9
9
  {
10
10
  path: '/',
11
- component: IndexPage,
11
+ component: HomePage,
12
12
  meta: {
13
13
  title: 'Vue3 Coding Standards',
14
14
  },
@@ -0,0 +1 @@
1
+ export const STORAGE_PREFIX = '{{projectName}}';
@@ -1,3 +1,15 @@
1
- import useConfigStore from '@/stores/modules/config';
1
+ import { createPinia as create } from 'pinia';
2
+ import { createPersistedState } from 'pinia-plugin-persistedstate';
3
+ import { STORAGE_PREFIX } from './constants';
4
+ export { useConfigStore } from './modules/config';
2
5
 
3
- export { useConfigStore };
6
+ export function createPinia() {
7
+ const pinia = create();
8
+ const persistedState = createPersistedState({
9
+ key: storeKey => `${STORAGE_PREFIX}-${storeKey}`,
10
+ });
11
+
12
+ pinia.use(persistedState);
13
+
14
+ return pinia;
15
+ }
@@ -9,7 +9,7 @@ const defaultState = {
9
9
  version: versionString,
10
10
  };
11
11
 
12
- export default defineStore('coding-standards-config', {
12
+ export const useConfigStore = defineStore('config', {
13
13
  state: () => defaultState,
14
14
  getters: {},
15
15
  actions: {},
@@ -0,0 +1,48 @@
1
+ :root {
2
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
3
+ line-height: 1.5;
4
+ font-weight: 400;
5
+
6
+ color-scheme: light dark;
7
+ color: rgba(255, 255, 255, 0.87);
8
+ background-color: #242424;
9
+
10
+ font-synthesis: none;
11
+ text-rendering: optimizeLegibility;
12
+ -webkit-font-smoothing: antialiased;
13
+ -moz-osx-font-smoothing: grayscale;
14
+ -webkit-text-size-adjust: 100%;
15
+ }
16
+
17
+ @media (prefers-color-scheme: light) {
18
+ :root {
19
+ background-color: #ffffff;
20
+ color: #213547;
21
+ }
22
+ }
23
+
24
+ body {
25
+ margin: 0;
26
+ display: flex;
27
+ place-items: center;
28
+ min-width: 320px;
29
+ min-height: 100vh;
30
+ }
31
+
32
+ #app {
33
+ max-width: 80rem;
34
+ margin: auto;
35
+ padding: 32px;
36
+ text-align: center;
37
+ }
38
+
39
+ a {
40
+ font-weight: 500;
41
+ text-decoration-color: inherit;
42
+ color: #646cff;
43
+ transition: color 150ms;
44
+
45
+ &:hover {
46
+ color: #535bf2;
47
+ }
48
+ }
@@ -0,0 +1 @@
1
+ @import './button.css';
@@ -0,0 +1,15 @@
1
+ button {
2
+ border-radius: 8px;
3
+ padding: 8px;
4
+ border-width: 1px;
5
+ border-color: transparent;
6
+ transition-property: border-color;
7
+ transition-duration: 300ms;
8
+ &:hover {
9
+ border-color: #646cff;
10
+ }
11
+ &:focus {
12
+ outline-width: 4px;
13
+ outline-color: -webkit-focus-ring-color;
14
+ }
15
+ }
@@ -0,0 +1,3 @@
1
+ @import './tailwind.css';
2
+ @import './base.css';
3
+ @import './common/all.css';
@@ -0,0 +1 @@
1
+ @import 'tailwindcss';
@@ -9,4 +9,5 @@ declare module '*.vue' {
9
9
  interface ImportMetaEnv extends Readonly<Record<string, string>> {
10
10
  readonly VITE_APP_VERSION: string;
11
11
  readonly VITE_APP_BUILD_EPOCH?: string;
12
+ readonly VITE_APP_MOCK?: string;
12
13
  }
@@ -4,10 +4,9 @@
4
4
  "exclude": ["src/**/__tests__/*"],
5
5
  "compilerOptions": {
6
6
  "composite": true,
7
- "noEmit": true,
8
- "baseUrl": "./",
7
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
9
8
  "paths": {
10
- "@/*": ["src/*"]
9
+ "@/*": ["./src/*"]
11
10
  }
12
11
  }
13
12
  }
@@ -2,10 +2,10 @@
2
2
  "extends": "@tsconfig/node22/tsconfig.json",
3
3
  "compilerOptions": {
4
4
  "composite": true,
5
- "skipLibCheck": true,
5
+ "noEmit": true,
6
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
6
7
  "module": "ESNext",
7
8
  "moduleResolution": "bundler",
8
- "resolveJsonModule": true,
9
9
  "types": ["node"]
10
10
  },
11
11
  "include": ["vite.config.ts", "package.json", "vitest.config.ts", "playwright.config.ts"]
@@ -1,8 +1,10 @@
1
1
  {
2
2
  "extends": "./tsconfig.app.json",
3
- "exclude": [],
4
3
  "compilerOptions": {
5
4
  "composite": true,
6
- "types": ["node", "vitest/globals"]
7
- }
5
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo",
6
+ "types": ["vitest/globals"]
7
+ },
8
+ "exclude": [],
9
+ "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "vitest.setup.ts"]
8
10
  }
@@ -1,15 +1,19 @@
1
1
  import { dirname, resolve } from 'node:path';
2
2
  import { fileURLToPath, URL } from 'node:url';
3
3
  import vueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
4
+ import tailwindcss from '@tailwindcss/vite';
4
5
  import vue from '@vitejs/plugin-vue';
5
6
  import { visualizer } from 'rollup-plugin-visualizer';
6
- import Components from 'unplugin-vue-components/vite';
7
7
  import { defineConfig } from 'vite';
8
8
  import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
9
9
  import packageJson from './package.json' with { type: 'json' };
10
10
 
11
11
  process.env.VITE_APP_VERSION = packageJson.version;
12
- process.env.NODE_ENV = process.env.MOCK ? 'mockServiceWorker' : process.env.NODE_ENV;
12
+
13
+ if (process.env.MOCK) {
14
+ process.env.VITE_APP_MOCK = 'service-worker';
15
+ }
16
+
13
17
  if (process.env.NODE_ENV === 'production') {
14
18
  process.env.VITE_APP_BUILD_EPOCH = Date.now().toString();
15
19
  }
@@ -18,15 +22,12 @@ export default defineConfig({
18
22
  base: './',
19
23
  plugins: [
20
24
  vue(),
21
- Components({
22
- dirs: ['src/components/common'],
23
- dts: 'src/components.d.ts',
24
- }),
25
+ tailwindcss(),
25
26
  vueI18nPlugin({
26
27
  include: resolve(dirname(fileURLToPath(import.meta.url)), 'src/locales/**'),
27
28
  }),
28
29
  createSvgIconsPlugin({
29
- iconDirs: [resolve(process.cwd(), 'src/assets/images/svgIcons')],
30
+ iconDirs: [resolve(process.cwd(), 'src/assets/svg-icons')],
30
31
  }),
31
32
  visualizer({ gzipSize: true }),
32
33
  ],
@@ -43,6 +44,12 @@ export default defineConfig({
43
44
  rollupOptions: {
44
45
  output: {
45
46
  chunkFileNames: 'chunks/[name]-[hash].js',
47
+ assetFileNames: 'assets/[name].[hash].[ext]',
48
+ entryFileNames: 'entries/[name].[hash].js',
49
+ manualChunks: {
50
+ core: ['vue', 'vue-router', 'pinia', 'pinia-plugin-persistedstate', 'vue-i18n'],
51
+ vender: ['axios', '@intlify/unplugin-vue-i18n/messages'],
52
+ },
46
53
  },
47
54
  },
48
55
  },
@@ -1,5 +1,3 @@
1
- /// <reference types="vitest" />
2
- import { fileURLToPath, URL } from 'node:url';
3
1
  import { defineConfig, mergeConfig } from 'vitest/config';
4
2
  import viteConfig from './vite.config';
5
3
 
@@ -10,8 +8,7 @@ export default mergeConfig(
10
8
  globals: true,
11
9
  environment: 'jsdom',
12
10
  include: ['src/__tests__/unit/**/*.test.ts'],
13
- root: fileURLToPath(new URL('./', import.meta.url)),
14
- setupFiles: ['src/__tests__/setup/unit-test.ts'],
11
+ setupFiles: ['./vitest.setup.ts'],
15
12
  coverage: {
16
13
  provider: 'v8',
17
14
  include: ['!src/main.ts', 'src/**/*.ts', 'src/**/*.vue'],
@@ -1,6 +1,12 @@
1
+ import { cleanup } from '@testing-library/vue';
1
2
  import { mswServer } from '@/mocks/server';
2
3
  import '@testing-library/jest-dom';
3
4
 
4
5
  beforeAll(() => mswServer.listen());
5
- afterEach(() => mswServer.resetHandlers());
6
+
7
+ afterEach(() => {
8
+ cleanup();
9
+ mswServer.resetHandlers();
10
+ });
11
+
6
12
  afterAll(() => mswServer.close());