@component-hook/create-app 1.1.1 → 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 (29) hide show
  1. package/dist/index.js +7 -7
  2. package/package.json +2 -2
  3. package/template-vue/.browserslistrc +10 -0
  4. package/template-vue/.github/workflows/preview.yml +1 -1
  5. package/template-vue/.husky/commit-msg +0 -2
  6. package/template-vue/.husky/pre-commit +0 -2
  7. package/template-vue/README.md.art +7 -9
  8. package/template-vue/_gitignore +0 -3
  9. package/template-vue/package.json +21 -25
  10. package/template-vue/postcss.config.js +2 -0
  11. package/template-vue/src/__tests__/e2e/home.spec.ts +28 -20
  12. package/template-vue/src/__tests__/unit/{components/home → pages/home/components}/HelloWorld.test.ts +1 -1
  13. package/template-vue/src/__tests__/unit/pages/home/index.test.ts +17 -0
  14. package/template-vue/src/components/common/index.ts +1 -0
  15. package/template-vue/src/main.ts +2 -4
  16. package/template-vue/src/pages/home/index.vue +2 -1
  17. package/template-vue/src/plugins/i18n.ts +2 -6
  18. package/template-vue/src/stores/constants.ts.art +1 -0
  19. package/template-vue/src/stores/index.ts +14 -2
  20. package/template-vue/src/stores/modules/{config.ts.art → config.ts} +1 -1
  21. package/template-vue/tsconfig.app.json +2 -3
  22. package/template-vue/tsconfig.node.json +2 -2
  23. package/template-vue/tsconfig.vitest.json +5 -3
  24. package/template-vue/vite.config.ts +7 -1
  25. package/template-vue/vitest.config.ts +1 -4
  26. package/template-vue/{src/__tests__/setup/unit-test.ts → vitest.setup.ts} +7 -1
  27. /package/template-vue/src/assets/{images/svg-icons → svg-icons}/vue.svg +0 -0
  28. /package/template-vue/src/components/{svg-icon → common/svg-icon}/index.ts +0 -0
  29. /package/template-vue/src/components/{svg-icon → common/svg-icon}/src/index.vue +0 -0
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  // src/index.ts
2
- import { readdirSync as readdirSync2, statSync } from "node:fs";
3
- import { readdir, readFile, writeFile } from "node:fs/promises";
4
- import path2 from "node:path";
5
- import { fileURLToPath } from "node:url";
2
+ import { readdirSync as readdirSync2, statSync } from "fs";
3
+ import { readdir, readFile, writeFile } from "fs/promises";
4
+ import path2 from "path";
5
+ import { fileURLToPath } from "url";
6
6
  import artTemplate from "art-template";
7
7
  import { copy, ensureDirSync } from "fs-extra/esm";
8
8
  import minimist from "minimist";
@@ -16,13 +16,13 @@ var GITHUB_ACTIONS = "GitHub Actions";
16
16
  var GITLAB_CI = "GitLab CI";
17
17
 
18
18
  // src/prompts.ts
19
- import { existsSync as existsSync2 } from "node:fs";
19
+ import { existsSync as existsSync2 } from "fs";
20
20
  import colors from "picocolors";
21
21
  import prompts from "prompts";
22
22
 
23
23
  // src/utils.ts
24
- import { existsSync, readdirSync } from "node:fs";
25
- import path from "node:path";
24
+ import { existsSync, readdirSync } from "fs";
25
+ import path from "path";
26
26
  import { remove } from "fs-extra/esm";
27
27
  function formatTargetDir(targetDir) {
28
28
  if (!targetDir) return targetDir;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@component-hook/create-app",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "Scaffolding a basic typescript project",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -14,7 +14,7 @@
14
14
  "dist"
15
15
  ],
16
16
  "engines": {
17
- "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
17
+ "node": ">=20.19.3"
18
18
  },
19
19
  "repository": {
20
20
  "type": "git",
@@ -0,0 +1,10 @@
1
+ # Click this link to view browser coverage https://browsersl.ist/#q=%3E+1.5%25%0Aios+%3E%3D+12%0Achrome+%3E%3D+49%0Anot+ie+%3C%3D+11%0Alast+2+versions%0Anot+dead
2
+
3
+ # Browsers that support
4
+
5
+ > 1.5%
6
+ ios >= 12
7
+ chrome >= 49
8
+ not ie <= 11
9
+ last 2 versions
10
+ not dead
@@ -1,4 +1,4 @@
1
- name: Prewiew Pull Request
1
+ name: Preview Pull Request
2
2
 
3
3
  on:
4
4
  pull_request:
@@ -1,3 +1 @@
1
- #!/bin/sh
2
-
3
1
  npx --no -- commitlint --edit ${1}
@@ -1,3 +1 @@
1
- #!/bin/sh
2
-
3
1
  npx lint-staged
@@ -28,19 +28,17 @@ This project is built with [vue3](https://vuejs.org/) + [vite](https://vite.dev/
28
28
  src/
29
29
  ├── __tests__/
30
30
  │ ├── __mocks__/
31
- │ ├── setup/
32
- │ │ └── unitTest.ts
33
31
  │ ├── e2e/*
34
32
  │ └── unit/*
35
- ├── apis/*
36
33
  ├── assets/*
37
- │ └── images/
38
- │ └── svg-icons
34
+ │ └── svg-icons
39
35
  │ └── vue.svg
40
36
  ├── components/
41
- │ └── svg-icon/
42
- │ ├── src
43
- │ │ └── index.vue
37
+ │ └── common
38
+ │ ├── svg-icon/
39
+ │ │ ├── src
40
+ │ │ │ └── index.vue
41
+ │ │ └── index.ts
44
42
  │ └── index.ts
45
43
  ├── constants/*
46
44
  ├── hooks/*
@@ -49,7 +47,7 @@ src/
49
47
  │ └── zh-CN.json
50
48
  ├── mocks/
51
49
  │ ├── handlers/*
52
- │ │ ├── apis/*
50
+ │ │ ├── modules/*
53
51
  │ │ └── index.ts
54
52
  │ │── browser.ts
55
53
  │ └── server.ts
@@ -25,9 +25,6 @@ dist-ssr
25
25
  *.sln
26
26
  *.sw?
27
27
 
28
- # Component auto import
29
- /src/components.d.ts
30
-
31
28
  # Test reports
32
29
  coverage
33
30
  /test-results/
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "vue-starter",
3
3
  "version": "0.0.0",
4
- "license": "MIT",
4
+ "private": true,
5
5
  "type": "module",
6
- "packageManager": "pnpm@10.10.0",
6
+ "packageManager": "pnpm@10.12.4",
7
7
  "scripts": {
8
8
  "dev": "vite",
9
9
  "dev:mock": "MOCK=true vite",
@@ -18,47 +18,43 @@
18
18
  "preview": "vite preview"
19
19
  },
20
20
  "dependencies": {
21
- "axios": "^1.9.0",
22
- "pinia": "^3.0.2",
21
+ "axios": "^1.10.0",
22
+ "pinia": "^3.0.3",
23
23
  "pinia-plugin-persistedstate": "^4.3.0",
24
- "vue": "^3.5.13",
25
- "vue-i18n": "^11.1.3",
24
+ "vue": "^3.5.17",
25
+ "vue-i18n": "^11.1.7",
26
26
  "vue-router": "^4.5.1"
27
27
  },
28
28
  "devDependencies": {
29
- "@component-hook/eslint-plugin": "1.1.0",
29
+ "@component-hook/eslint-plugin": "1.1.1",
30
30
  "@intlify/unplugin-vue-i18n": "^6.0.8",
31
- "@playwright/test": "^1.52.0",
32
- "@tailwindcss/vite": "^4.1.6",
31
+ "@playwright/test": "^1.53.1",
32
+ "@tailwindcss/vite": "^4.1.11",
33
33
  "@testing-library/jest-dom": "^6.6.3",
34
34
  "@testing-library/user-event": "^14.6.1",
35
35
  "@testing-library/vue": "^8.1.0",
36
- "@tsconfig/node22": "^22.0.1",
37
- "@types/node": "^22.15.17",
36
+ "@tsconfig/node22": "^22.0.2",
37
+ "@types/node": "^22.15.33",
38
38
  "@vitejs/plugin-vue": "^5.2.4",
39
- "@vitest/coverage-v8": "^3.1.3",
39
+ "@vitest/coverage-v8": "^3.2.4",
40
40
  "@vue/tsconfig": "^0.7.0",
41
41
  "autoprefixer": "^10.4.21",
42
42
  "cssnano": "^7.0.7",
43
- "eslint": "^9.26.0",
43
+ "eslint": "^9.29.0",
44
44
  "jsdom": "^26.1.0",
45
- "msw": "^2.8.2",
46
- "postcss": "^8.5.3",
45
+ "msw": "^2.10.2",
46
+ "postcss": "^8.5.6",
47
+ "postcss-preset-env": "^10.2.4",
47
48
  "postcss-pxtorem": "^6.1.0",
48
- "prettier": "^3.5.3",
49
- "rollup-plugin-visualizer": "^5.13.1",
50
- "tailwindcss": "^4.1.6",
49
+ "prettier": "^3.6.2",
50
+ "rollup-plugin-visualizer": "^6.0.3",
51
+ "tailwindcss": "^4.1.11",
51
52
  "typescript": "^5.8.3",
52
53
  "vite": "^6.3.5",
53
54
  "vite-plugin-svg-icons": "^2.0.1",
54
- "vitest": "^3.1.3",
55
+ "vitest": "^3.2.4",
55
56
  "vue-tsc": "^2.2.10"
56
57
  },
57
- "browserslist": [
58
- "> 1%",
59
- "last 2 versions",
60
- "not dead"
61
- ],
62
58
  "msw": {
63
59
  "workerDirectory": "public"
64
60
  },
@@ -66,6 +62,6 @@
66
62
  "@commitlint/cli": "^19.8.1",
67
63
  "@commitlint/config-conventional": "^19.8.1",
68
64
  "husky": "^9.1.7",
69
- "lint-staged": "^16.0.0"
65
+ "lint-staged": "^16.1.2"
70
66
  }
71
67
  }
@@ -1,5 +1,6 @@
1
1
  import autoprefixer from 'autoprefixer';
2
2
  import cssnano from 'cssnano';
3
+ import postcssPresetEnv from 'postcss-preset-env';
3
4
  import postcssPxtorem from 'postcss-pxtorem';
4
5
 
5
6
  export default {
@@ -10,6 +11,7 @@ export default {
10
11
  propList: ['*'],
11
12
  selectorBlackList: ['norem'],
12
13
  }),
14
+ postcssPresetEnv({ stage: 3 }),
13
15
  ...(process.env.NODE_ENV === 'production' ? [cssnano({ preset: 'default' })] : []),
14
16
  ],
15
17
  };
@@ -4,20 +4,24 @@ test.beforeEach(async ({ page }) => {
4
4
  await page.goto('/');
5
5
  });
6
6
 
7
- test('click Vite logo open Vite official website blank tab', async ({ page, context }) => {
8
- await page.getByRole('link', { name: 'Vite logo' }).click();
9
- const newPage = await context.waitForEvent('page');
7
+ test('click Vite logo open Vite official website blank tab', async ({ page }) => {
8
+ const link = page.getByRole('link', { name: /vite logo/i });
10
9
 
11
- await newPage.waitForLoadState('load');
12
- await expect(newPage).toHaveTitle('Vite | Next Generation Frontend Tooling');
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');
13
15
  });
14
16
 
15
- test('click Vue logo open Vue official website blank tab', async ({ page, context }) => {
16
- await page.getByTitle('#icon-vue').click();
17
- const newPage = await context.waitForEvent('page');
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())]);
18
22
 
19
- await newPage.waitForLoadState('load');
20
- await expect(newPage).toHaveTitle('Vue.js - The Progressive JavaScript Framework | Vue.js');
23
+ await popup.waitForLoadState();
24
+ await expect(popup).toHaveTitle('Vue.js - The Progressive JavaScript Framework | Vue.js');
21
25
  });
22
26
 
23
27
  test('homepage count button interact', async ({ page }) => {
@@ -34,20 +38,24 @@ test('locale change interact', async ({ page }) => {
34
38
  await expect(page.getByRole('button', { name: 'English' })).toBeVisible();
35
39
  });
36
40
 
37
- test('click create-vue link open Vue quick start blank tab', async ({ page, context }) => {
38
- await page.getByRole('link', { name: 'create-vue' }).click();
39
- const newPage = await context.waitForEvent('page');
41
+ test('click create-vue link open Vue quick start blank tab', async ({ page }) => {
42
+ const link = page.getByRole('link', { name: 'create-vue' });
40
43
 
41
- await newPage.waitForLoadState('load');
42
- await expect(newPage).toHaveTitle('Quick Start | Vue.js');
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');
43
49
  });
44
50
 
45
- test('click Volar link open language-tools github blank tab', async ({ page, context }) => {
46
- await page.getByRole('link', { name: 'Volar' }).click();
47
- const newPage = await context.waitForEvent('page');
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())]);
48
56
 
49
- await newPage.waitForLoadState('load');
50
- await expect(newPage).toHaveTitle(
57
+ await popup.waitForLoadState();
58
+ await expect(popup).toHaveTitle(
51
59
  'GitHub - vuejs/language-tools: ⚡ High-performance Vue language tooling based-on Volar.js',
52
60
  );
53
61
  });
@@ -5,7 +5,7 @@ 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';
@@ -1,10 +1,9 @@
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
8
  import '@/styles/index.css';
10
9
 
@@ -14,10 +13,9 @@ if (import.meta.env.VITE_APP_MOCK === 'service-worker') {
14
13
  worker.start();
15
14
  }
16
15
 
17
- const pinia = createPinia();
18
16
  const app = createApp(App);
17
+ const pinia = createPinia();
19
18
 
20
- pinia.use(piniaPluginPersistedstate);
21
19
  app.use(pinia);
22
20
  app.use(router);
23
21
  app.use(i18NPlugin);
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { SvgIcon } from '@/components/svg-icon';
2
+ import { SvgIcon } from '@/components/common';
3
3
  import HelloWorld from './components/HelloWorld.vue';
4
4
  </script>
5
5
 
@@ -18,6 +18,7 @@ import HelloWorld from './components/HelloWorld.vue';
18
18
  <a
19
19
  href="https://vuejs.org/"
20
20
  target="_blank"
21
+ aria-label="Vue link"
21
22
  >
22
23
  <svg-icon
23
24
  name="vue"
@@ -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;
@@ -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('{{projectName}}-config', {
12
+ export const useConfigStore = defineStore('config', {
13
13
  state: () => defaultState,
14
14
  getters: {},
15
15
  actions: {},
@@ -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
  }
@@ -27,7 +27,7 @@ export default defineConfig({
27
27
  include: resolve(dirname(fileURLToPath(import.meta.url)), 'src/locales/**'),
28
28
  }),
29
29
  createSvgIconsPlugin({
30
- iconDirs: [resolve(process.cwd(), 'src/assets/images/svg-icons')],
30
+ iconDirs: [resolve(process.cwd(), 'src/assets/svg-icons')],
31
31
  }),
32
32
  visualizer({ gzipSize: true }),
33
33
  ],
@@ -44,6 +44,12 @@ export default defineConfig({
44
44
  rollupOptions: {
45
45
  output: {
46
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
+ },
47
53
  },
48
54
  },
49
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());