create-banana 1.0.2 → 1.1.0

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.
package/bin/index.js CHANGED
@@ -15,6 +15,9 @@ import addMain from '#utils/template/base/main.js';
15
15
  import { select } from '@inquirer/prompts';
16
16
  import addPiniaPluginPersistedstate from '#utils/template/pinia/piniaPluginPersistedstate.js';
17
17
  import chalk from 'chalk';
18
+ import boxen from 'boxen';
19
+ import addVueRouter from '#utils/template/vueRouter/vueRouter.js';
20
+ import addAboutView from '#utils/template/vueRouter/aboutView.js';
18
21
 
19
22
  // print BANANA in rainbow colors
20
23
  const log = console.log;
@@ -34,12 +37,14 @@ const feats = await checkbox({
34
37
  { name: 'Eslint', value: 'eslint' },
35
38
  { name: 'Prettier', value: 'prettier' },
36
39
  { name: 'Pinia', value: 'pinia' },
40
+ { name: 'Vue-Router', value: 'vue-router' },
37
41
  ],
38
42
  });
39
43
 
40
44
  const useEslint = feats.includes('eslint');
41
45
  const usePrettier = feats.includes('prettier');
42
46
  const usePinia = feats.includes('pinia');
47
+ const useVueRouter = feats.includes('vue-router');
43
48
 
44
49
  let usePiniaPluginPersistedstate = false;
45
50
  if (usePinia) {
@@ -54,8 +59,18 @@ if (usePinia) {
54
59
 
55
60
  // TODO: 把一类型的功能整合到一起
56
61
  await createBaseProject(projectName);
57
- await addAppVue(projectName, usePinia, usePiniaPluginPersistedstate);
58
- await addMain(projectName, usePinia, usePiniaPluginPersistedstate);
62
+ await addAppVue(
63
+ projectName,
64
+ usePinia,
65
+ usePiniaPluginPersistedstate,
66
+ useVueRouter
67
+ );
68
+ await addMain(
69
+ projectName,
70
+ usePinia,
71
+ usePiniaPluginPersistedstate,
72
+ useVueRouter
73
+ );
59
74
 
60
75
  await addPinia(projectName, usePinia, usePiniaPluginPersistedstate);
61
76
  await addPiniaPluginPersistedstate(projectName, usePiniaPluginPersistedstate);
@@ -65,6 +80,9 @@ await addEslintConfig(projectName, usePrettier, useEslint);
65
80
 
66
81
  await addPrettier(projectName, usePrettier);
67
82
 
83
+ await addVueRouter(projectName, useVueRouter);
84
+ await addAboutView(projectName, usePiniaPluginPersistedstate, useVueRouter);
85
+
68
86
  // 参考create-vue的颜色
69
87
  const greenColor = [22, 198, 12];
70
88
 
@@ -75,15 +93,15 @@ log(
75
93
  )
76
94
  );
77
95
 
78
- const eslintStr = chalk
79
- .rgb(...greenColor)
80
- .underline(` cd ${projectName} && pnpm i && pnpm lint && pnpm dev \n`);
81
- const prettierStr = chalk
82
- .rgb(...greenColor)
83
- .underline(` cd ${projectName} && pnpm i && pnpm format && pnpm dev \n`);
84
- const noFormatStr = chalk
85
- .rgb(...greenColor)
86
- .underline(` cd ${projectName} && pnpm i && pnpm dev \n`);
96
+ const eslintStr = chalk.rgb(...greenColor)(
97
+ `\n cd ${projectName} && pnpm i && pnpm lint && pnpm dev \n`
98
+ );
99
+ const prettierStr = chalk.rgb(...greenColor)(
100
+ `\n cd ${projectName} && pnpm i && pnpm format && pnpm dev \n`
101
+ );
102
+ const noFormatStr = chalk.rgb(...greenColor)(
103
+ `\n cd ${projectName} && pnpm i && pnpm dev \n`
104
+ );
87
105
 
88
106
  let outStr = '';
89
107
  useEslint
@@ -92,12 +110,29 @@ useEslint
92
110
  ? (outStr = prettierStr)
93
111
  : (outStr = noFormatStr);
94
112
 
95
- log(outStr);
113
+ log(
114
+ chalk.cyan(
115
+ boxen(outStr, {
116
+ title: 'commands',
117
+ titleAlignment: 'center',
118
+ })
119
+ ),
120
+ '\n'
121
+ );
122
+
96
123
  // 初始化Git
97
124
  log(rainbowGradient('Initialize Git using the following command:\n'));
98
125
  // TODO: 以后有commitizen再改这里
99
126
  log(
100
- chalk
101
- .rgb(...greenColor)
102
- .underline(' git init && git add . && git commit -m "Initial commit" ')
127
+ chalk.cyan(
128
+ boxen(
129
+ chalk.rgb(...greenColor)(
130
+ '\n git init && git add . && git commit -m "Initial commit" \n'
131
+ ),
132
+ {
133
+ title: 'commands',
134
+ titleAlignment: 'center',
135
+ }
136
+ )
137
+ )
103
138
  );
@@ -1,34 +1,23 @@
1
1
  import js from '@eslint/js';
2
2
  import globals from 'globals';
3
+ import pluginVue from 'eslint-plugin-vue';
3
4
  import json from '@eslint/json';
4
5
  import { defineConfig, globalIgnores } from 'eslint/config';
6
+
5
7
  import prettierPlugin from 'eslint-plugin-prettier';
8
+ import prettierConfig from 'eslint-config-prettier';
6
9
 
7
10
  export default defineConfig([
8
11
  {
9
- files: ['**/*.{js,mjs,cjs}'],
10
- plugins: { js, prettier: prettierPlugin },
12
+ files: ['**/*.{js,mjs,cjs,vue}'],
13
+ plugins: { js },
11
14
  extends: ['js/recommended'],
12
15
  languageOptions: { globals: globals.node },
13
- rules: {
14
- 'prettier/prettier': [
15
- 'warn',
16
- {
17
- printWidth: 80,
18
- tabWidth: 2,
19
- useTabs: false,
20
- semi: true,
21
- singleQuote: true,
22
- quoteProps: 'as-needed',
23
- jsxSingleQuote: false,
24
- trailingComma: 'es5',
25
- bracketSpacing: true,
26
- bracketSameLine: false,
27
- arrowParens: 'always',
28
- endOfLine: 'auto',
29
- },
30
- ],
31
- },
16
+ },
17
+ {
18
+ files: ['**/*.vue'],
19
+ plugins: { vue: pluginVue },
20
+ extends: [pluginVue.configs['flat/essential']],
32
21
  },
33
22
  {
34
23
  files: ['**/*.json'],
@@ -37,6 +26,15 @@ export default defineConfig([
37
26
  extends: ['json/recommended'],
38
27
  },
39
28
 
29
+ // 全局 Prettier 配置
30
+ {
31
+ plugins: { prettier: prettierPlugin },
32
+ extends: [prettierConfig],
33
+ rules: {
34
+ 'prettier/prettier': ['warn'], // 不符合 prettier 风格时显示 warning
35
+ },
36
+ },
37
+
40
38
  globalIgnores([
41
39
  'node_modules/*',
42
40
  'dist/*',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-banana",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/TMname1/create-banana.git"
@@ -27,6 +27,7 @@
27
27
  "license": "ISC",
28
28
  "dependencies": {
29
29
  "@inquirer/prompts": "^8.1.0",
30
+ "boxen": "^8.0.1",
30
31
  "chalk": "^5.6.2",
31
32
  "ejs": "^3.1.10",
32
33
  "figlet": "^1.9.4",
@@ -37,7 +38,9 @@
37
38
  "@eslint/json": "^0.14.0",
38
39
  "cz-conventional-changelog": "^3.3.0",
39
40
  "eslint": "^9.39.2",
41
+ "eslint-config-prettier": "^10.1.8",
40
42
  "eslint-plugin-prettier": "^5.5.4",
43
+ "eslint-plugin-vue": "^10.6.2",
41
44
  "globals": "^16.5.0",
42
45
  "husky": "^8.0.0",
43
46
  "lint-staged": "^16.2.7",
@@ -15,7 +15,7 @@ export default defineConfig([
15
15
  files: ['**/*.{js,mjs,cjs,vue}'],
16
16
  plugins: { js },
17
17
  extends: ['js/recommended'],
18
- languageOptions: { globals: { ...globals.browser } },
18
+ languageOptions: { globals: globals.browser },
19
19
  },
20
20
  {
21
21
  files: ["**/*.vue"],
@@ -11,6 +11,11 @@
11
11
  useKeyStore
12
12
  } from './stores/key'
13
13
  <% } %>
14
+ <% if(useVueRouter) { %>import {
15
+ useRoute
16
+ }
17
+ from 'vue-router'
18
+ <% } %>
14
19
 
15
20
  <% if(usePinia) { %>
16
21
  const counterStore = useCounterStore()
@@ -18,6 +23,9 @@
18
23
  <% if(usePiniaPluginPersistedstate) { %>
19
24
  const keyStore = useKeyStore()
20
25
  <% } %>
26
+ <% if(useVueRouter) { %>
27
+ const route = useRoute()
28
+ <% } %>
21
29
  </script>
22
30
 
23
31
  <template>
@@ -29,11 +37,35 @@
29
37
  <% if(usePinia) { %><button class="piniaBtn" @click="counterStore.increment">Count is:
30
38
  {{ counterStore.count }}</button><% } %>
31
39
  <% if(usePiniaPluginPersistedstate) { %><input class="persistInp" v-model="keyStore.key" placeholder="Enter a key to persist" /><% } %>
40
+ <% if(useVueRouter) { %>
41
+ <!-- 按钮切换页面 -->
42
+ <div>
43
+ <button class="routerBtn">
44
+ <router-link to="/home">
45
+ <span :class="{ 'active-link': route.name === 'home' }">
46
+ Home
47
+ </span>
48
+ </router-link>
49
+ </button>
50
+ <span style="margin: 0 5px">|</span>
51
+ <button class="routerBtn">
52
+ <router-link to="/about">
53
+ <span :class="{ 'active-link': route.name === 'about' }">
54
+ About
55
+ </span>
56
+ </router-link>
57
+ </button>
58
+ </div><% } %>
32
59
  </div>
33
60
  </header>
34
61
 
35
62
  <main>
63
+ <% if(useVueRouter) { %>
64
+ <router-view />
65
+ <% } %>
66
+ <% if(!useVueRouter) { %>
36
67
  <TheWelcome />
68
+ <% } %>
37
69
  </main>
38
70
  </template>
39
71
 
@@ -76,6 +108,24 @@
76
108
  <%
77
109
  }
78
110
 
111
+ %><%if(useVueRouter) {
112
+ %>.routerBtn {
113
+ margin-top: 1rem;
114
+ padding: 0.5rem 1rem;
115
+ font-size: 1rem;
116
+ border: none;
117
+ background: none;
118
+ }
119
+
120
+ .active-link {
121
+ font-weight: bold;
122
+ color: hsla(160, 100%, 30%, 1);
123
+ border-bottom: 2px solid hsla(160, 100%, 37%, 1);
124
+ }
125
+
126
+ <%
127
+ }
128
+
79
129
  %>@media (min-width: 1024px) {
80
130
  header {
81
131
  display: flex;
@@ -3,5 +3,16 @@ import { createApp } from 'vue'
3
3
  import App from './App.vue'
4
4
  <% if(usePinia) { %>import { createPinia } from 'pinia'<% } %>
5
5
  <% if(usePiniaPluginPersistedstate) { %>import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'<% } %>
6
+ <% if(useVueRouter) { %>import router from './router/index.js';<% } %>
6
7
 
7
- createApp(App)<% if(usePinia) { %>.use(createPinia()<% if(usePiniaPluginPersistedstate) { %>.use(piniaPluginPersistedstate)<% } %>)<% } %>.mount('#app')
8
+ createApp(App)
9
+ <% if(usePinia) { %>
10
+ .use(createPinia()
11
+ <% if(usePiniaPluginPersistedstate) { %>
12
+ .use(piniaPluginPersistedstate)
13
+ <% } %>
14
+ )
15
+ <% } %>
16
+ <% if(useVueRouter) { %>
17
+ .use(router)
18
+ <% } %>.mount('#app')
@@ -4,7 +4,7 @@ import { defineStore } from 'pinia';
4
4
  export const useKeyStore = defineStore(
5
5
  'key',
6
6
  () => {
7
- const key = ref('');
7
+ const key = ref('Hello Pinia Persisted State!');
8
8
  return { key };
9
9
  },
10
10
  { persist: true }
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <div>
3
+ <h1><slot></slot></h1>
4
+ </div>
5
+ </template>
6
+
7
+ <style scoped>
8
+ div {
9
+ height: 100%;
10
+ display: flex;
11
+ align-items: center;
12
+ }
13
+ </style>
@@ -0,0 +1,5 @@
1
+ {
2
+ "dependencies": {
3
+ "vue-router": "^4.6.4"
4
+ }
5
+ }
@@ -0,0 +1,32 @@
1
+ import { createRouter, createWebHistory } from 'vue-router';
2
+ import HomeView from '../views/HomeView.vue';
3
+
4
+ const router = createRouter({
5
+ // TODO: 根据需要选择 history 模式
6
+ history: createWebHistory(import.meta.env.BASE_URL),
7
+ routes: [
8
+ // redirect root to /home
9
+ { path: '/', redirect: '/home' },
10
+ {
11
+ path: '/home',
12
+ name: 'home',
13
+ component: HomeView,
14
+ },
15
+ {
16
+ path: '/about',
17
+ name: 'about',
18
+ // route level code-splitting
19
+ // this generates a separate chunk (About.[hash].js) for this route
20
+ // which is lazy-loaded when the route is visited.
21
+ component: () => import('../views/AboutView.vue'),
22
+ },
23
+ // 404 Not Found route
24
+ {
25
+ path: '/:pathMatch(.*)*',
26
+ name: 'notFound',
27
+ component: () => import('../views/NotFound.vue'),
28
+ },
29
+ ],
30
+ });
31
+
32
+ export default router;
@@ -0,0 +1,21 @@
1
+ <script setup>
2
+ import TitleText from '@/components/TitleText.vue';
3
+ <% if(usePiniaPluginPersistedstate) { %>
4
+ import {
5
+ useKeyStore
6
+ } from '@/stores/key.js';
7
+ const keyStore = useKeyStore();
8
+ <% } %>
9
+ </script>
10
+
11
+ <template>
12
+ <TitleText>This is an about page
13
+ <% if(usePiniaPluginPersistedstate) { %>
14
+ ,<div>
15
+ the key is:
16
+ <span style="color: white; font-weight: bold">
17
+ {{ keyStore.key }}</span>
18
+ </div>
19
+ <% } %>
20
+ </TitleText>
21
+ </template>
@@ -0,0 +1,7 @@
1
+ <script setup>
2
+ import TheWelcome from '../components/TheWelcome.vue';
3
+ </script>
4
+
5
+ <template>
6
+ <TheWelcome></TheWelcome>
7
+ </template>
@@ -0,0 +1,7 @@
1
+ <script setup>
2
+ import TitleText from '@/components/TitleText.vue';
3
+ </script>
4
+
5
+ <template>
6
+ <TitleText>404 Not Found</TitleText>
7
+ </template>
@@ -3,6 +3,7 @@
3
3
  // 若选择不覆盖则退出程序
4
4
  import fs from 'fs-extra';
5
5
  import { select } from '@inquirer/prompts';
6
+ import chalk from 'chalk';
6
7
 
7
8
  const confirmPathExists = async (projectName, projectDir) => {
8
9
  try {
@@ -10,7 +11,7 @@ const confirmPathExists = async (projectName, projectDir) => {
10
11
  if (await fs.pathExists(projectDir)) {
11
12
  // 如果存在就提示是否要覆盖
12
13
  const isOverwrite = await select({
13
- message: `The target folder "${projectName}" is not empty. Overwrite?`,
14
+ message: `The target folder "${projectName}" is not empty. ${chalk.yellow('Overwrite')}?`,
14
15
  choices: [
15
16
  { name: 'Yes', value: true },
16
17
  { name: 'No', value: false },
@@ -7,7 +7,8 @@ import path from 'path';
7
7
  const addAppVue = async (
8
8
  projectName,
9
9
  usePinia,
10
- usePiniaPluginPersistedstate
10
+ usePiniaPluginPersistedstate,
11
+ useVueRouter
11
12
  ) => {
12
13
  await fs.writeFile(
13
14
  path.join(process.cwd(), projectName, 'src', 'App.vue'),
@@ -19,6 +20,7 @@ const addAppVue = async (
19
20
  {
20
21
  usePinia,
21
22
  usePiniaPluginPersistedstate,
23
+ useVueRouter,
22
24
  }
23
25
  )
24
26
  );
@@ -4,7 +4,12 @@ import { templatePath } from '#utils/URL.js';
4
4
  import fs from 'fs-extra';
5
5
  import path from 'path';
6
6
 
7
- const addMain = async (projectName, usePinia, usePiniaPluginPersistedstate) => {
7
+ const addMain = async (
8
+ projectName,
9
+ usePinia,
10
+ usePiniaPluginPersistedstate,
11
+ useVueRouter
12
+ ) => {
8
13
  await fs.writeFile(
9
14
  path.join(process.cwd(), projectName, 'src', 'main.js'),
10
15
  ejs.render(
@@ -15,6 +20,7 @@ const addMain = async (projectName, usePinia, usePiniaPluginPersistedstate) => {
15
20
  {
16
21
  usePinia,
17
22
  usePiniaPluginPersistedstate,
23
+ useVueRouter,
18
24
  }
19
25
  )
20
26
  );
@@ -0,0 +1,29 @@
1
+ import ejs from 'ejs';
2
+ import { templatePath } from '#utils/URL.js';
3
+ import fs from 'fs-extra';
4
+ import path from 'path';
5
+
6
+ const addAboutView = async (
7
+ projectName,
8
+ usePiniaPluginPersistedstate,
9
+ useVueRouter
10
+ ) => {
11
+ if (!useVueRouter) return;
12
+ await fs.writeFile(
13
+ path.join(process.cwd(), projectName, 'src', 'views', 'AboutView.vue'),
14
+ ejs.render(
15
+ await fs.readFile(
16
+ path.join(templatePath, 'vue-router', 'views', 'AboutView.vue.ejs'),
17
+ 'utf-8'
18
+ ),
19
+ {
20
+ usePiniaPluginPersistedstate,
21
+ }
22
+ )
23
+ );
24
+ await fs.remove(
25
+ path.join(process.cwd(), projectName, 'src', 'AboutView.vue.ejs')
26
+ );
27
+ };
28
+
29
+ export default addAboutView;
@@ -0,0 +1,46 @@
1
+ import { templatePath } from '../../URL.js';
2
+ import path from 'path';
3
+ import fs from 'fs-extra';
4
+
5
+ const addVueRouter = async (projectName, flag) => {
6
+ // 没有选择vueRouter则直接返回
7
+ if (!flag) return;
8
+ // 路径
9
+ const templateVueRouterPath = path.join(templatePath, 'vue-router');
10
+ const targetPath = path.join(process.cwd(), projectName);
11
+ const targetSrcPath = path.join(targetPath, 'src');
12
+ const targetPackageJsonPath = path.join(targetPath, 'package.json');
13
+
14
+ // 文件
15
+ const targetPkg = await fs.readJson(targetPackageJsonPath);
16
+ const vueRouterPkg = await fs.readJson(
17
+ path.join(templateVueRouterPath, 'package.json')
18
+ );
19
+
20
+ // 添加package.json的内容
21
+ targetPkg.dependencies = {
22
+ ...targetPkg.dependencies,
23
+ ...vueRouterPkg.dependencies,
24
+ };
25
+
26
+ await fs.writeJson(targetPackageJsonPath, targetPkg, { spaces: 2 });
27
+
28
+ // 复制components文件
29
+ fs.copySync(
30
+ path.join(templateVueRouterPath, 'components'),
31
+ path.join(targetSrcPath, 'components'),
32
+ { overwrite: false }
33
+ );
34
+ // 复制router文件
35
+ fs.copySync(
36
+ path.join(templateVueRouterPath, 'router'),
37
+ path.join(targetSrcPath, 'router')
38
+ );
39
+ // 复制views文件
40
+ fs.copySync(
41
+ path.join(templateVueRouterPath, 'views'),
42
+ path.join(targetSrcPath, 'views')
43
+ );
44
+ };
45
+
46
+ export default addVueRouter;