create-bubbles 0.1.7 → 0.1.8

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 (40) hide show
  1. package/dist/index.js +4 -3
  2. package/package.json +1 -1
  3. package/template-taro-vue-eslint/.editorconfig +12 -0
  4. package/template-taro-vue-eslint/.env +0 -0
  5. package/template-taro-vue-eslint/.env.development +4 -0
  6. package/template-taro-vue-eslint/.env.production +4 -0
  7. package/template-taro-vue-eslint/.vscode/settings.json +57 -0
  8. package/template-taro-vue-eslint/babel.config.js +12 -0
  9. package/template-taro-vue-eslint/commitlint.config.mjs +1 -0
  10. package/template-taro-vue-eslint/config/dev.ts +10 -0
  11. package/template-taro-vue-eslint/config/index.ts +129 -0
  12. package/template-taro-vue-eslint/config/output-root.ts +11 -0
  13. package/template-taro-vue-eslint/config/prod.ts +39 -0
  14. package/template-taro-vue-eslint/config/release.ts +121 -0
  15. package/template-taro-vue-eslint/eslint.config.mjs +17 -0
  16. package/template-taro-vue-eslint/key/private.wxac3f99d8814754aa.key +27 -0
  17. package/template-taro-vue-eslint/lefthook.yaml +13 -0
  18. package/template-taro-vue-eslint/package.json +113 -0
  19. package/template-taro-vue-eslint/patches/@tarojs__plugin-mini-ci.patch +13 -0
  20. package/template-taro-vue-eslint/pnpm-workspace.yaml +2 -0
  21. package/template-taro-vue-eslint/project.config.json +16 -0
  22. package/template-taro-vue-eslint/src/app.config.ts +11 -0
  23. package/template-taro-vue-eslint/src/app.css +1 -0
  24. package/template-taro-vue-eslint/src/app.ts +14 -0
  25. package/template-taro-vue-eslint/src/index.html +17 -0
  26. package/template-taro-vue-eslint/src/pages/index/index.config.ts +3 -0
  27. package/template-taro-vue-eslint/src/pages/index/index.module.scss +4 -0
  28. package/template-taro-vue-eslint/src/pages/index/index.vue +18 -0
  29. package/template-taro-vue-eslint/src/store/index.ts +10 -0
  30. package/template-taro-vue-eslint/src/store/modules/user.ts +15 -0
  31. package/template-taro-vue-eslint/src/store/taroStorage.ts +7 -0
  32. package/template-taro-vue-eslint/src/utils/env.ts +6 -0
  33. package/template-taro-vue-eslint/src/utils/request/core/index.ts +192 -0
  34. package/template-taro-vue-eslint/src/utils/request/core/utils.ts +30 -0
  35. package/template-taro-vue-eslint/src/utils/request/index.ts +44 -0
  36. package/template-taro-vue-eslint/tsconfig.json +30 -0
  37. package/template-taro-vue-eslint/types/components.d.ts +12 -0
  38. package/template-taro-vue-eslint/types/global.d.ts +31 -0
  39. package/template-taro-vue-eslint/types/vue.d.ts +10 -0
  40. package/template-taro-vue-eslint/unocss.config.ts +38 -0
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import e from"node:fs";import t from"node:path";import*as n from"@clack/prompts";import r from"gradient-string";import i from"mri";import a from"cross-spawn";import{fileURLToPath as o}from"node:url";const s={vue:r([`#42B883`,`#42B883`]),react:r([`#087EA4`,`#087EA4`]),others:r([`#8B5CF6`,`#A855F7`])},c=i(process.argv.slice(2),{alias:{h:`help`,t:`template`},boolean:[`help`,`overwrite`],string:[`template`]}),l=process.cwd(),u=`\
1
+ import e from"node:fs";import t from"node:path";import{fileURLToPath as n}from"node:url";import*as r from"@clack/prompts";import i from"cross-spawn";import a from"gradient-string";import o from"mri";const s={vue:a([`#42B883`,`#42B883`]),react:a([`#087EA4`,`#087EA4`]),taro:a([`#0000C2`,`#fff`]),others:a([`#8B5CF6`,`#A855F7`])},c=o(process.argv.slice(2),{alias:{h:`help`,t:`template`},boolean:[`help`,`overwrite`],string:[`template`]}),l=process.cwd(),u=`\
2
2
  Usage: create-bubbles [OPTION]... [DIRECTORY]
3
3
 
4
4
  Create a new Bubbles project in JavaScript or TypeScript.
@@ -10,8 +10,9 @@ Options:
10
10
  Available templates:
11
11
  ${s.vue(`vue-rsbuild-biome vue`)}
12
12
  ${s.vue(`vue-rolldown-oxc vue`)}
13
+ ${s.taro(`taro-vue-eslint taro`)}
13
14
  ${s.react(`react-rsbuild-biome react`)}
14
- ${s.react(`react-rolldown-oxc react`)}`,d=e=>e.trim().replace(/\/+$/g,``),f=e=>{if(!e)return;let t=e.split(` `)[0].split(`/`);return{name:t[0],version:t[1]}},p=t=>{let n=e.readdirSync(t);return n.length===0||n.length===1&&n[0]===`.git`},m=async n=>{await Promise.all(e.readdirSync(n).filter(e=>e!==`.git`).map(r=>e.promises.rm(t.resolve(n,r),{recursive:!0,force:!0})))},h=e=>/^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(e),g=e=>e.trim().toLowerCase().replace(/\s+/g,`-`).replace(/^[._]/,``).replace(/[^a-z\d\-~]+g/,`-`),_=[{name:`vue`,display:`Vue`,color:s.vue,variants:[{name:`vue-vite-eslint`,display:`vite + eslint`,color:s.vue},{name:`vue-rsbuild-biome`,display:`rsbuild + biome`,color:s.vue},{name:`vue-vite-oxc`,display:`rolldown + oxc`,color:s.vue},{name:`vue-vite-biome`,display:`vite + biome`,color:s.vue}]},{name:`react`,display:`React`,color:s.react,variants:[{name:`react-rsbuild-biome`,display:`rsbuild-biome`,color:s.react}]},{name:`others`,display:`Others`,color:s.others,variants:[{name:`create-eletron-vite`,display:`Electron ↗`,color:s.others,customCommand:`pnpm create electron-vite@latest TARGET_DIR`}]}],v=_.map(e=>e.variants.map(e=>`${e.name}`)).reduce((e,t)=>e.concat(t),[]),y=(e,t)=>{console.log(`💦customCommand`,e,t);let n=t?t.name:`npm`,r=n===`yarn`&&t?.version.startsWith(`1.`);return e.replace(/^npm create (?:-- )?/,()=>n===`bun`?`bun x create-`:n===`pnpm`?`pnpm create `:e.startsWith(`npm create -- `)?`${n} create -- `:`${n} create `).replace(`@latest`,()=>r?``:`@latest`).replace(/^npm exec/,()=>n===`pnpm`?`pnpm dlx`:n===`yarn`&&!r?`yarn dlx`:n===`bun`?`bun x`:`npm exec`)},b={_gitignore:`.gitignore`},x=(n,r)=>{e.mkdirSync(r,{recursive:!0});for(let i of e.readdirSync(n))S(t.resolve(n,i),t.resolve(r,i))},S=(t,n)=>{e.statSync(t).isDirectory()?x(t,n):e.copyFileSync(t,n)},C=(t,n)=>{let r=e.readFileSync(t,`utf-8`);e.writeFileSync(t,n(r),`utf-8`)},w=(e,n)=>{C(t.resolve(e,`package.json`),e=>e.replace(/"@vitejs\/plugin-react": ".+?"/,`"@vitejs/plugin-react-swc": "^4.0.1"`)),C(t.resolve(e,`vite.config.${n?`ts`:`js`}`),e=>e.replace(`@vitejs/plugin-react`,`@vitejs/plugin-react-swc`))};(async()=>{console.log(c);let i=c._[0]?d(c._[0]):void 0,x=c.template,C=c.overwrite,T=`bubbles-project`;if(c.help){console.log(u);return}let E=f(process.env.npm_config_user_agent),D=()=>n.cancel(`Operation cancelled`),O=i;if(!O){let e=await n.text({message:`Project name`,defaultValue:T,placeholder:T,validate:e=>e.length===0||d(e).length>0?void 0:`Invalid project name`});if(n.isCancel(e))return D();O=d(e)}if(e.existsSync(O)&&!p(O)){let e=C?`yes`:await n.select({message:O===`.`?`Current directory`:`Target directory "${O}" is not empty. Please choose how to proceed:`,options:[{label:`${s.vue(`Cancel operation`)}`,value:`no`},{label:`Remove existing files and continue`,value:`yes`},{label:`Ignore files and continue`,value:`ignore`}]});if(n.isCancel(e))return D();switch(e){case`yes`:m(O);break;case`no`:D();return}}let k=t.basename(t.resolve(O));if(!h(k)){let e=await n.text({message:`Package name is invalid. please input again:`,defaultValue:g(k),placeholder:g(k),validate(e){if(!h(e))return`Invalid package.json name`}});if(n.isCancel(e))return D();k=e}let A=x,j=!1;if(x&&!v.includes(x)&&(A=void 0,j=!0),!A){let e=await n.select({message:j?`"${x}" isn't a valia template. please choose from below:`:`Select a framework`,options:_.map(e=>{let t=e.color;return{label:t(e.display),value:e}})});if(n.isCancel(e))return D();console.log(`💦pkgInfo`,E);let t=await n.select({message:`Select a variant:`,options:e.variants.map(e=>{let t=e.color,n=e.customCommand?y(e.customCommand,E).replace(/ TARGET_DIR$/,``):void 0;return{label:t(e.display||e.name),value:e.name,hint:n}})});if(n.isCancel(t))return D();A=t}let M=t.join(l,O);e.mkdirSync(M,{recursive:!0});let N=!1;A.includes(`-swc`)&&(N=!0,A=A.replace(`-swc`,``));let P=E?E.name:`npm`,{customCommand:F}=_.flatMap(e=>e.variants).find(e=>e.name===A)??{};if(F){let[e,...t]=y(F,E).split(` `),n=t.map(e=>e.replace(`TARGET_DIR`,()=>O));console.log(`💦replacedArgs`,n);let{status:r}=a.sync(e,n,{stdio:`inherit`});process.exit(r??0)}n.log.step(`scaffolding project in ${M}...`);let I=t.resolve(o(import.meta.url),`../..`,`template-${A}`),L=(n,r)=>{let i=t.join(M,b[n]??n);r?e.writeFileSync(i,r):S(t.join(I,n),i)},R=e.readdirSync(I);for(let e of R)e!==`package.json`&&L(e);let z=JSON.parse(e.readFileSync(t.join(I,`package.json`),`utf-8`));z.name=k,L(`package.json`,`${JSON.stringify(z,null,2)}\n`),N&&w(M,A.endsWith(`-ts`));let B=``,V=t.relative(l,M);switch(console.log(`💦cwd`,l),console.log(`💦root`,M),console.log(`💦cdProjectName`,V),B+=`Done. Now run:
15
+ ${s.react(`react-rolldown-oxc react`)}`,d=e=>e.trim().replace(/\/+$/g,``),f=e=>{if(!e)return;let t=e.split(` `)[0].split(`/`);return{name:t[0],version:t[1]}},p=t=>{let n=e.readdirSync(t);return n.length===0||n.length===1&&n[0]===`.git`},m=async n=>{await Promise.all(e.readdirSync(n).filter(e=>e!==`.git`).map(r=>e.promises.rm(t.resolve(n,r),{recursive:!0,force:!0})))},h=e=>/^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(e),g=e=>e.trim().toLowerCase().replace(/\s+/g,`-`).replace(/^[._]/,``).replace(/[^a-z\d\-~]+g/,`-`),_=[{name:`vue`,display:`Vue`,color:s.vue,variants:[{name:`vue-vite-eslint`,display:`vite + eslint`,color:s.vue},{name:`vue-rsbuild-biome`,display:`rsbuild + biome`,color:s.vue},{name:`vue-vite-oxc`,display:`rolldown + oxc`,color:s.vue},{name:`vue-vite-biome`,display:`vite + biome`,color:s.vue}]},{name:`react`,display:`React`,color:s.react,variants:[{name:`react-rsbuild-biome`,display:`rsbuild-biome`,color:s.react}]},{name:`taro`,display:`Taro`,color:s.taro,variants:[{name:`taro-vue-eslint`,display:`taro-vue + eslint`,color:s.taro}]},{name:`others`,display:`Others`,color:s.others,variants:[{name:`create-eletron-vite`,display:`Electron ↗`,color:s.others,customCommand:`pnpm create electron-vite@latest TARGET_DIR`}]}],v=_.map(e=>e.variants.map(e=>`${e.name}`)).reduce((e,t)=>e.concat(t),[]),y=(e,t)=>{console.log(`💦customCommand`,e,t);let n=t?t.name:`npm`,r=n===`yarn`&&t?.version.startsWith(`1.`);return e.replace(/^npm create (?:-- )?/,()=>n===`bun`?`bun x create-`:n===`pnpm`?`pnpm create `:e.startsWith(`npm create -- `)?`${n} create -- `:`${n} create `).replace(`@latest`,()=>r?``:`@latest`).replace(/^npm exec/,()=>n===`pnpm`?`pnpm dlx`:n===`yarn`&&!r?`yarn dlx`:n===`bun`?`bun x`:`npm exec`)},b={_gitignore:`.gitignore`},x=(n,r)=>{e.mkdirSync(r,{recursive:!0});for(let i of e.readdirSync(n))S(t.resolve(n,i),t.resolve(r,i))},S=(t,n)=>{e.statSync(t).isDirectory()?x(t,n):e.copyFileSync(t,n)},C=(t,n)=>{let r=e.readFileSync(t,`utf-8`);e.writeFileSync(t,n(r),`utf-8`)},w=(e,n)=>{C(t.resolve(e,`package.json`),e=>e.replace(/"@vitejs\/plugin-react": ".+?"/,`"@vitejs/plugin-react-swc": "^4.0.1"`)),C(t.resolve(e,`vite.config.${n?`ts`:`js`}`),e=>e.replace(`@vitejs/plugin-react`,`@vitejs/plugin-react-swc`))};(async()=>{console.log(c);let o=c._[0]?d(c._[0]):void 0,x=c.template,C=c.overwrite,T=`bubbles-project`;if(c.help){console.log(u);return}let E=f(process.env.npm_config_user_agent),D=()=>r.cancel(`Operation cancelled`),O=o;if(!O){let e=await r.text({message:`Project name`,defaultValue:T,placeholder:T,validate:e=>e.length===0||d(e).length>0?void 0:`Invalid project name`});if(r.isCancel(e))return D();O=d(e)}if(e.existsSync(O)&&!p(O)){let e=C?`yes`:await r.select({message:O===`.`?`Current directory`:`Target directory "${O}" is not empty. Please choose how to proceed:`,options:[{label:`${s.vue(`Cancel operation`)}`,value:`no`},{label:`Remove existing files and continue`,value:`yes`},{label:`Ignore files and continue`,value:`ignore`}]});if(r.isCancel(e))return D();switch(e){case`yes`:m(O);break;case`no`:D();return}}let k=t.basename(t.resolve(O));if(!h(k)){let e=await r.text({message:`Package name is invalid. please input again:`,defaultValue:g(k),placeholder:g(k),validate(e){if(!h(e))return`Invalid package.json name`}});if(r.isCancel(e))return D();k=e}let A=x,j=!1;if(x&&!v.includes(x)&&(A=void 0,j=!0),!A){let e=await r.select({message:j?`"${x}" isn't a valia template. please choose from below:`:`Select a framework`,options:_.map(e=>{let t=e.color;return{label:t(e.display),value:e}})});if(r.isCancel(e))return D();console.log(`💦pkgInfo`,E);let t=await r.select({message:`Select a variant:`,options:e.variants.map(e=>{let t=e.color,n=e.customCommand?y(e.customCommand,E).replace(/ TARGET_DIR$/,``):void 0;return{label:t(e.display||e.name),value:e.name,hint:n}})});if(r.isCancel(t))return D();A=t}let M=t.join(l,O);e.mkdirSync(M,{recursive:!0});let N=!1;A.includes(`-swc`)&&(N=!0,A=A.replace(`-swc`,``));let P=E?E.name:`npm`,{customCommand:F}=_.flatMap(e=>e.variants).find(e=>e.name===A)??{};if(F){let[e,...t]=y(F,E).split(` `),n=t.map(e=>e.replace(`TARGET_DIR`,()=>O));console.log(`💦replacedArgs`,n);let{status:r}=i.sync(e,n,{stdio:`inherit`});process.exit(r??0)}r.log.step(`scaffolding project in ${M}...`);let I=t.resolve(n(import.meta.url),`../..`,`template-${A}`),L=(n,r)=>{let i=t.join(M,b[n]??n);r?e.writeFileSync(i,r):S(t.join(I,n),i)},R=e.readdirSync(I);for(let e of R)e!==`package.json`&&L(e);let z=JSON.parse(e.readFileSync(t.join(I,`package.json`),`utf-8`));z.name=k,L(`package.json`,`${JSON.stringify(z,null,2)}\n`),N&&w(M,A.endsWith(`-ts`));let B=``,V=t.relative(l,M);switch(console.log(`💦cwd`,l),console.log(`💦root`,M),console.log(`💦cdProjectName`,V),B+=`Done. Now run:
15
16
  `,M!==l&&(B+=`\n cd ${V.includes(` `)?`"${V}"`:V} `),P){case`yarn`:B+=`
16
17
  yarn`,B+=`
17
- yarn dev`;break;default:B+=r([`pink`,`white`])(`\n ${P} install`),B+=r([`pink`,`white`])(`\n ${P} run dev`);break}n.outro(B)})().catch(e=>{console.error(`💦`,e)});export{};
18
+ yarn dev`;break;default:B+=a([`pink`,`white`])(`\n ${P} install`),B+=a([`pink`,`white`])(`\n ${P} run dev`);break}r.outro(B)})().catch(e=>{console.error(`💦`,e)});export{};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bubbles",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "type": "module",
5
5
  "author": "bubbles plant",
6
6
  "bin": {
@@ -0,0 +1,12 @@
1
+ # http://editorconfig.org
2
+ root = true
3
+
4
+ [*]
5
+ indent_style = space
6
+ indent_size = 2
7
+ charset = utf-8
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
10
+
11
+ [*.md]
12
+ trim_trailing_whitespace = false
File without changes
@@ -0,0 +1,4 @@
1
+ # 配置文档参考 https://taro-docs.jd.com/docs/next/env-mode-config
2
+ TARO_WEAPP_ID = 'wxac3f99d8814754aa'
3
+ # 接口地址
4
+ TARO_API_URL = 'https://mfsl.com.cn/api'
@@ -0,0 +1,4 @@
1
+ # 配置文档参考 https://taro-docs.jd.com/docs/next/env-mode-config
2
+ TARO_WEAPP_ID = 'wxac3f99d8814754aa'
3
+ # 接口地址
4
+ TARO_API_URL = 'https://mfsl.com.cn/api'
@@ -0,0 +1,57 @@
1
+ {
2
+ // Disable the default formatter, use eslint instead
3
+ "oxc.enable": false,
4
+ "biome.enabled": false,
5
+ "prettier.enable": false,
6
+ "editor.formatOnSave": false,
7
+
8
+ // Auto fix
9
+ "editor.codeActionsOnSave": {
10
+ "source.fixAll.eslint": "explicit",
11
+ "source.organizeImports": "never"
12
+ },
13
+
14
+ // Silent the stylistic rules in your IDE, but still auto fix them
15
+ "eslint.rules.customizations": [
16
+ { "rule": "style/*", "severity": "off", "fixable": true },
17
+ { "rule": "format/*", "severity": "off", "fixable": true },
18
+ { "rule": "*-indent", "severity": "off", "fixable": true },
19
+ { "rule": "*-spacing", "severity": "off", "fixable": true },
20
+ { "rule": "*-spaces", "severity": "off", "fixable": true },
21
+ { "rule": "*-order", "severity": "off", "fixable": true },
22
+ { "rule": "*-dangle", "severity": "off", "fixable": true },
23
+ { "rule": "*-newline", "severity": "off", "fixable": true },
24
+ { "rule": "*quotes", "severity": "off", "fixable": true },
25
+ { "rule": "*semi", "severity": "off", "fixable": true }
26
+ ],
27
+
28
+ // Enable eslint for all supported languages
29
+ "eslint.validate": [
30
+ "javascript",
31
+ "javascriptreact",
32
+ "typescript",
33
+ "typescriptreact",
34
+ "vue",
35
+ "html",
36
+ "markdown",
37
+ "json",
38
+ "json5",
39
+ "jsonc",
40
+ "yaml",
41
+ "toml",
42
+ "xml",
43
+ "gql",
44
+ "graphql",
45
+ "astro",
46
+ "svelte",
47
+ "css",
48
+ "less",
49
+ "scss",
50
+ "pcss",
51
+ "postcss"
52
+ ],
53
+ "cSpell.words": [
54
+ "Alova",
55
+ "tarojs"
56
+ ]
57
+ }
@@ -0,0 +1,12 @@
1
+ // babel-preset-taro 更多选项和默认值:
2
+ // https://docs.taro.zone/docs/next/babel-config
3
+ module.exports = {
4
+ presets: [
5
+ ['taro', {
6
+ framework: 'vue3',
7
+ ts: true,
8
+ compiler: 'webpack5',
9
+ useBuiltIns: process.env.TARO_ENV === 'h5' ? 'usage' : false
10
+ }]
11
+ ]
12
+ }
@@ -0,0 +1 @@
1
+ export default { extends: ["@commitlint/config-conventional"] };
@@ -0,0 +1,10 @@
1
+ import type { UserConfigExport } from '@tarojs/cli'
2
+
3
+ export default {
4
+ logger: {
5
+ quiet: false,
6
+ stats: true,
7
+ },
8
+ mini: {},
9
+ h5: {},
10
+ } satisfies UserConfigExport<'webpack5'>
@@ -0,0 +1,129 @@
1
+ import type { UserConfigExport } from '@tarojs/cli'
2
+ import process from 'node:process'
3
+ import NutUIResolver from '@nutui/auto-import-resolver'
4
+ import { defineConfig } from '@tarojs/cli'
5
+ import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin'
6
+ import UnoCSS from 'unocss/webpack'
7
+ import Components from 'unplugin-vue-components/webpack'
8
+ import devConfig from './dev'
9
+ import { outputRootMap } from './output-root'
10
+ import prodConfig from './prod'
11
+ import { CIPluginFn } from './release'
12
+
13
+ // https://taro-docs.jd.com/docs/next/config#defineconfig-辅助函数
14
+ export default defineConfig<'webpack5'>(async (merge, { command, mode }) => {
15
+ const baseConfig: UserConfigExport<'webpack5'> = {
16
+ projectName: 'myApp',
17
+ date: '2026-2-24',
18
+ designWidth: (input: any) => {
19
+ // 配置 NutUI 375 尺寸
20
+ if (input?.file?.replace(/\\+/g, '/').indexOf('@nutui') > -1) {
21
+ return 375
22
+ }
23
+ // 全局使用 Taro 默认的 750 尺寸
24
+ return 750
25
+ },
26
+ deviceRatio: {
27
+ 640: 2.34 / 2,
28
+ 750: 1,
29
+ 375: 2,
30
+ 828: 1.81 / 2,
31
+ },
32
+ sourceRoot: 'src',
33
+ outputRoot: outputRootMap[process.env.TARO_ENV] || 'dist/other',
34
+ plugins: [
35
+ '@tarojs/plugin-generator',
36
+ '@tarojs/plugin-html',
37
+ ['@tarojs/plugin-mini-ci', CIPluginFn],
38
+ ],
39
+ defineConstants: {
40
+ },
41
+ copy: {
42
+ patterns: [
43
+ ],
44
+ options: {
45
+ },
46
+ },
47
+ framework: 'vue3',
48
+ compiler: 'webpack5',
49
+ cache: {
50
+ enable: false, // Webpack 持久化缓存配置,建议开启。默认配置请参考:https://docs.taro.zone/docs/config-detail#cache
51
+ },
52
+ mini: {
53
+ postcss: {
54
+ pxtransform: {
55
+ enable: true,
56
+ config: {
57
+
58
+ },
59
+ },
60
+ cssModules: {
61
+ enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true
62
+ config: {
63
+ namingPattern: 'module', // 转换模式,取值为 global/module
64
+ generateScopedName: '[name]__[local]___[hash:base64:5]',
65
+ },
66
+ },
67
+ },
68
+ webpackChain(chain) {
69
+ chain.resolve.plugin('tsconfig-paths').use(TsconfigPathsPlugin)
70
+ chain.plugin('unplugin-vue-components').use(Components({
71
+ resolvers: [NutUIResolver({ taro: true })],
72
+ dts: './types/components.d.ts',
73
+ }))
74
+ chain.plugin('unocss').use(UnoCSS())
75
+ },
76
+ },
77
+ h5: {
78
+ publicPath: '/',
79
+ staticDirectory: 'static',
80
+ output: {
81
+ filename: 'js/[name].[hash:8].js',
82
+ chunkFilename: 'js/[name].[chunkhash:8].js',
83
+ },
84
+ miniCssExtractPluginOption: {
85
+ ignoreOrder: true,
86
+ filename: 'css/[name].[hash].css',
87
+ chunkFilename: 'css/[name].[chunkhash].css',
88
+ },
89
+ postcss: {
90
+ autoprefixer: {
91
+ enable: true,
92
+ config: {},
93
+ },
94
+ cssModules: {
95
+ enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true
96
+ config: {
97
+ namingPattern: 'module', // 转换模式,取值为 global/module
98
+ generateScopedName: '[name]__[local]___[hash:base64:5]',
99
+ },
100
+ },
101
+ },
102
+ webpackChain(chain) {
103
+ chain.resolve.plugin('tsconfig-paths').use(TsconfigPathsPlugin)
104
+ chain.plugin('unplugin-vue-components').use(Components({
105
+ resolvers: [NutUIResolver({ taro: true })],
106
+ dts: './types/components.d.ts',
107
+ }))
108
+ chain.plugin('unocss').use(UnoCSS())
109
+ },
110
+ },
111
+ rn: {
112
+ appName: 'taroDemo',
113
+ postcss: {
114
+ cssModules: {
115
+ enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
116
+ },
117
+ },
118
+ },
119
+ }
120
+
121
+ process.env.BROWSERSLIST_ENV = process.env.NODE_ENV
122
+
123
+ if (process.env.NODE_ENV === 'development') {
124
+ // 本地开发构建配置(不混淆压缩)
125
+ return merge({}, baseConfig, devConfig)
126
+ }
127
+ // 生产构建配置(默认开启压缩混淆等)
128
+ return merge({}, baseConfig, prodConfig)
129
+ })
@@ -0,0 +1,11 @@
1
+ export const outputRootMap = {
2
+ 'weapp': 'dist/weapp',
3
+ 'swan': 'dist/swan',
4
+ 'alipay': 'dist/alipay',
5
+ 'tt': 'dist/tt',
6
+ 'h5': 'dist/h5',
7
+ 'rn': 'dist/rn',
8
+ 'qq': 'dist/qq',
9
+ 'jd': 'dist/jd',
10
+ 'harmony-hybrid': 'dist/harmony-hybrid',
11
+ }
@@ -0,0 +1,39 @@
1
+ import type { UserConfigExport } from '@tarojs/cli'
2
+
3
+ export default {
4
+ mini: {},
5
+ h5: {
6
+ compile: {
7
+ include: [
8
+ // 确保产物为 es5
9
+ filename => /node_modules\/(?!(@babel|core-js|style-loader|css-loader|react|react-dom))/.test(filename),
10
+ ],
11
+ },
12
+ /**
13
+ * WebpackChain 插件配置
14
+ * @docs https://github.com/neutrinojs/webpack-chain
15
+ */
16
+ // webpackChain (chain) {
17
+ // /**
18
+ // * 如果 h5 端编译后体积过大,可以使用 webpack-bundle-analyzer 插件对打包体积进行分析。
19
+ // * @docs https://github.com/webpack-contrib/webpack-bundle-analyzer
20
+ // */
21
+ // chain.plugin('analyzer')
22
+ // .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, [])
23
+ // /**
24
+ // * 如果 h5 端首屏加载时间过长,可以使用 prerender-spa-plugin 插件预加载首页。
25
+ // * @docs https://github.com/chrisvfritz/prerender-spa-plugin
26
+ // */
27
+ // const path = require('path')
28
+ // const Prerender = require('prerender-spa-plugin')
29
+ // const staticDir = path.join(__dirname, '..', 'dist')
30
+ // chain
31
+ // .plugin('prerender')
32
+ // .use(new Prerender({
33
+ // staticDir,
34
+ // routes: [ '/pages/index/index' ],
35
+ // postProcess: (context) => ({ ...context, outputPath: path.join(staticDir, 'index.html') })
36
+ // }))
37
+ // }
38
+ },
39
+ } satisfies UserConfigExport<'webpack5'>
@@ -0,0 +1,121 @@
1
+ import { execSync } from 'node:child_process'
2
+ import * as fs from 'node:fs'
3
+ import * as path from 'node:path'
4
+ import process from 'node:process'
5
+ import { devtools } from 'vue'
6
+
7
+ /**
8
+ * 获取package.json中的版本号
9
+ */
10
+ function getPackageVersion(): string {
11
+ try {
12
+ const packagePath = path.join(process.cwd(), 'package.json')
13
+ const packageContent = fs.readFileSync(packagePath, 'utf8')
14
+ const packageData = JSON.parse(packageContent)
15
+ return packageData.version || '1.0.0'
16
+ }
17
+ catch {
18
+ console.warn('⚠️ 获取package.json版本号失败,使用默认版本 1.0.0')
19
+ return '1.0.0'
20
+ }
21
+ }
22
+
23
+ /**
24
+ * 获取最新的Git提交信息
25
+ */
26
+ function getLatestCommitMessage(): string {
27
+ try {
28
+ const message = execSync('git log -1 --pretty=%B', { encoding: 'utf8' }).trim()
29
+ return message || '版本更新'
30
+ }
31
+ catch {
32
+ console.warn('⚠️ 获取Git提交信息失败,使用默认描述')
33
+ return '版本更新'
34
+ }
35
+ }
36
+
37
+ /**
38
+ * 获取当前分支名
39
+ */
40
+ function getCurrentBranch(): string {
41
+ try {
42
+ return execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim()
43
+ }
44
+ catch {
45
+ return 'unknown'
46
+ }
47
+ }
48
+
49
+ /**
50
+ * 获取提交者信息
51
+ */
52
+ function getCommitAuthor(): string {
53
+ try {
54
+ return execSync('git log -1 --pretty=%an', { encoding: 'utf8' }).trim()
55
+ }
56
+ catch {
57
+ return 'unknown'
58
+ }
59
+ }
60
+
61
+ /**
62
+ * CI插件配置函数
63
+ * 自动读取版本号和提交信息
64
+ * @returns CIOptions配置
65
+ */
66
+ export async function CIPluginFn() {
67
+ // 动态获取版本信息
68
+ const version = getPackageVersion()
69
+ const commitMessage = getLatestCommitMessage()
70
+ const branch = getCurrentBranch()
71
+ const author = getCommitAuthor()
72
+
73
+ // 构建发布描述
74
+ const desc = `${commitMessage}\n\n📦 版本: ${version}\n🌿 分支: ${branch}\n👤 提交者: ${author}\n⏰ 发布时间: ${new Date().toLocaleString('zh-CN')}`
75
+
76
+ console.warn('🚀 CI发布配置:')
77
+ console.warn(`📦 版本号: ${version}`)
78
+ console.warn(`📝 提交信息: ${commitMessage}`)
79
+ console.warn(`🌿 分支: ${branch}`)
80
+ console.warn(`👤 提交者: ${author}`)
81
+
82
+ /**
83
+ * @typedef { import("@tarojs/plugin-mini-ci").CIOptions } CIOptions
84
+ * @type {CIOptions}
85
+ */
86
+ return {
87
+ weapp: {
88
+ appid:
89
+ process.env.TARO_APP_MODE === 'development' ? 'wxac3f99d8814754aa' : 'wxac3f99d8814754aa',
90
+ privateKeyPath:
91
+ process.env.TARO_APP_MODE === 'development'
92
+ ? 'key/private.wxac3f99d8814754aa.key'
93
+ : 'key/private.wxac3f99d8814754aa.key',
94
+ devToolsInstallPath: `C:\\Program Files (x86)\\Tencent\\微信web开发者工具`,
95
+ },
96
+ // tt: {
97
+ // email: '字节小程序邮箱',
98
+ // password: '字节小程序密码',
99
+ // },
100
+ // alipay: {
101
+ // appid: '支付宝小程序appid',
102
+ // toolId: '工具id',
103
+ // privateKeyPath: '密钥文件相对项目根目录的相对路径,例如 key/pkcs8-private-pem',
104
+ // },
105
+ // dd: {
106
+ // appid: '钉钉小程序appid,即钉钉开放平台后台应用管理的 MiniAppId 选项',
107
+ // token: '令牌,从钉钉后台获取',
108
+ // },
109
+ // swan: {
110
+ // token: '鉴权需要的token令牌',
111
+ // },
112
+ // 动态版本号
113
+ version,
114
+ // 动态版本发布描述
115
+ desc,
116
+ }
117
+ }
118
+
119
+ // export const config = {
120
+ // plugin: [['@tarojs/plugin-mini-ci', CIPluginFn]],
121
+ // }
@@ -0,0 +1,17 @@
1
+ import antfu from '@antfu/eslint-config'
2
+
3
+ export default antfu(
4
+ {
5
+ extends: ['taro/vue3'],
6
+ formatters: true,
7
+ unocss: true,
8
+ vue: true,
9
+ typescript: true,
10
+ stylistic: {
11
+ indent: 2, // 4, or 'tab'
12
+ quotes: 'single', // or 'double'
13
+ },
14
+ // Parse the `.gitignore` file to get the ignores, on by default
15
+ gitignore: true,
16
+ },
17
+ )
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEpQIBAAKCAQEA8F9CtEfBvL1L6KpXvIbXVPktUpBQWrM6336lYy4RI7LYeQqu
3
+ 6FTuc9Xj/efpLHk25bO2B0/cbnm+fOsKqAOF/7q9KPuLVVNkCMlDrte62wuHXuU7
4
+ c3mKNjZ1LfUCeM1oVi4w1rYYm9m9D1trHvvCSc+UJvjQeE1Zbd9ExH12eCllkU0n
5
+ ARUAP2XoRNeXEShJiQ8EHc89Pko1v1hc3h6eOh0y4lBfqiasr/yj2Bkuc3WDSu3J
6
+ iUHFeKBIkaH7dAG8m86SlmS4YU8av8XXQGa67iyEt2QpC+GWola4mFNCQ3hdjPqb
7
+ uq/MQCrg4XBUYNVt+qbr8+jKymYo12j9R5AQ1QIDAQABAoIBAQCK1LpWHcvMExkw
8
+ vJIIFWlxbqm6shd3C2XJiABGFGlZ0QYugvkav1MqHDOehr+qLCiE6xMLjhimxjI7
9
+ PBXfjIlsdpKihQaotY1ldbld1sPZmAML0CJSQ7SMM0/ix0wyMZE9lVgn6uyzt0L3
10
+ B7oLHyXMM9RB3huqICKyzu2M/1nZdBDktVtAX13oVcbnlsQ+2JIhrG/YoP12lPbt
11
+ vP8DjAOuQODW+DKI20Etc+jfizNQ6XBuMtcNQM3/hHU2hGn8l7dZDVmnTaTgVfie
12
+ HCtneTfiptiA4M/CD6efkTfxRkiVIdYEfgHOKuXYaPD7ySd1N6w87dJFcN6uU3bV
13
+ LZkSBFhRAoGBAPhhIlgJKbMjeTmoyZJRMFd4Wm94RWJm9OlimiFRxHH76Rs1Add+
14
+ 7Gle9yoU9GKVp5B1hj1fdkQ0Su6zzi4+nzMHuVVLJDtQLtq3WE2C6oJoGeAVDIys
15
+ lVF1L5JDp2KLzlpzvJhqkf/WSerUHtKKugC7QUwIMlvR7+hJFfEijTLDAoGBAPe/
16
+ O+EHKL/lVZIWNq4P4HUKFk/YJgQgYt5Y+7fn7qulYPqmgm+ZDLFBBp+IFk3F25L2
17
+ D+NhcYFtVCfhR3LYeWynZNZamHZ6zT7zRG9I9wR5oxxDYNTdsTg5L4oVmK5Stslo
18
+ C/MpSn1Q6tNyWIvGlbH8DH3JAoFDfd+KXy3M/8SHAoGAPp3uVJdqxdiplRmyR4rk
19
+ Twjuc6+0fkxKbhQHm2LLzZieeddxMWy0GRRx51AFFF16MvcN8qcAX813HpqB3jK3
20
+ W9wUoyYgajuatFUIk/HvQRURgOaNlWFk+3Y5mfwoVLW+PhtzblFfoUnatLLpWlbS
21
+ 8aBDo/FlELTqcHsMZxA43JUCgYEA4SA8aFqaE+5w2MQowfkZbSFSbxGqUfuf/A5+
22
+ BnrSrdUlD/947bH1D6lYPGVsZxXRVnUUsPmeLA9N9sNGqry9cheWkRZYDum+UmK6
23
+ oCl8let2ZbtwZV5iqQWGBoNjb50oDlLm8PpnfwKlsKjqf3FgHBE+xJqBFTdgTV6u
24
+ 6K6tCEcCgYEAioTQ/Mq23w25O0cRo4c+m1YsrwMOjo+lPXfpTlO2DZVSVqkAEuf1
25
+ zMD33nQwIjimnzjhOOQdOi95ky98p+3cDA/QOZC8XsGp9UUqxM8d7gdgkhj/7iQ1
26
+ MQFlqx4BiY0sk7Aszx9EfPHS5vvntwyqv9+M5iOw4mdj10OdMovxczc=
27
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,13 @@
1
+ pre-commit:
2
+ commands:
3
+ check:
4
+ glob: '*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc,vue}'
5
+ run: pnpm lint:fix {staged_files}
6
+ stage_fixed: true
7
+
8
+ commit-msg:
9
+ commands:
10
+ lint commit message:
11
+ run: npx commitlint --edit {1}
12
+
13
+
@@ -0,0 +1,113 @@
1
+ {
2
+ "name": "taro-vue-eslint",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "description": "vue-taro-eslint",
6
+ "author": "",
7
+ "templateInfo": {
8
+ "name": "default",
9
+ "typescript": true,
10
+ "css": "Sass",
11
+ "framework": "Vue3"
12
+ },
13
+ "scripts": {
14
+ "prepare": "lefthook install",
15
+ "new": "taro new",
16
+ "build:weapp": "taro build --type weapp --open",
17
+ "build:swan": "taro build --type swan",
18
+ "build:alipay": "taro build --type alipay",
19
+ "build:tt": "taro build --type tt",
20
+ "build:h5": "taro build --type h5",
21
+ "build:rn": "taro build --type rn",
22
+ "build:qq": "taro build --type qq",
23
+ "build:jd": "taro build --type jd",
24
+ "build:harmony-hybrid": "taro build --type harmony-hybrid",
25
+ "dev:weapp": "npm run build:weapp -- --watch",
26
+ "dev:swan": "npm run build:swan -- --watch",
27
+ "dev:alipay": "npm run build:alipay -- --watch",
28
+ "dev:tt": "npm run build:tt -- --watch",
29
+ "dev:h5": "npm run build:h5 -- --watch",
30
+ "dev:rn": "npm run build:rn -- --watch",
31
+ "dev:qq": "npm run build:qq -- --watch",
32
+ "dev:jd": "npm run build:jd -- --watch",
33
+ "dev:harmony-hybrid": "npm run build:harmony-hybrid -- --watch",
34
+ "postinstall": "weapp-tw patch",
35
+ "lint": "eslint",
36
+ "lint:fix": "eslint --fix"
37
+ },
38
+ "browserslist": {
39
+ "development": [
40
+ "defaults and fully supports es6-module",
41
+ "maintained node versions"
42
+ ],
43
+ "production": [
44
+ "last 3 versions",
45
+ "Android >= 4.1",
46
+ "ios >= 8"
47
+ ]
48
+ },
49
+ "dependencies": {
50
+ "@alova/adapter-taro": "^2.0.14",
51
+ "@babel/runtime": "^7.24.4",
52
+ "@nutui/nutui-taro": "^4.3.14",
53
+ "@nutui/touch-emulator": "^1.0.0",
54
+ "@tarojs/components": "4.1.11",
55
+ "@tarojs/helper": "4.1.11",
56
+ "@tarojs/plugin-framework-vue3": "4.1.11",
57
+ "@tarojs/plugin-html": "4.1.11",
58
+ "@tarojs/plugin-platform-alipay": "4.1.11",
59
+ "@tarojs/plugin-platform-h5": "4.1.11",
60
+ "@tarojs/plugin-platform-harmony-hybrid": "4.1.11",
61
+ "@tarojs/plugin-platform-jd": "4.1.11",
62
+ "@tarojs/plugin-platform-qq": "4.1.11",
63
+ "@tarojs/plugin-platform-swan": "4.1.11",
64
+ "@tarojs/plugin-platform-tt": "4.1.11",
65
+ "@tarojs/plugin-platform-weapp": "4.1.11",
66
+ "@tarojs/runtime": "4.1.11",
67
+ "@tarojs/shared": "4.1.11",
68
+ "@tarojs/taro": "4.1.11",
69
+ "alova": "^3.5.0",
70
+ "pinia": "^3.0.4",
71
+ "pinia-plugin-persistedstate": "^4.7.1",
72
+ "vue": "^3.0.0"
73
+ },
74
+ "devDependencies": {
75
+ "@antfu/eslint-config": "^7.4.3",
76
+ "@babel/core": "^7.24.4",
77
+ "@babel/plugin-transform-class-properties": "7.25.9",
78
+ "@commitlint/cli": "^20.4.2",
79
+ "@commitlint/config-conventional": "^20.4.2",
80
+ "@nutui/auto-import-resolver": "^1.0.0",
81
+ "@tarojs/cli": "4.1.11",
82
+ "@tarojs/plugin-generator": "4.1.11",
83
+ "@tarojs/plugin-mini-ci": "^4.1.11",
84
+ "@tarojs/taro-loader": "4.1.11",
85
+ "@tarojs/test-utils-vue3": "^0.1.1",
86
+ "@tarojs/webpack5-runner": "4.1.11",
87
+ "@types/minimatch": "^5",
88
+ "@types/node": "^18",
89
+ "@types/webpack-env": "^1.13.6",
90
+ "@unocss/webpack": "0.58.9",
91
+ "@vue/babel-plugin-jsx": "^1.2.2",
92
+ "@vue/compiler-sfc": "^3.0.0",
93
+ "autoprefixer": "^10.4.24",
94
+ "babel-preset-taro": "4.1.11",
95
+ "css-loader": "^7.1.1",
96
+ "eslint": "^10.0.2",
97
+ "eslint-config-taro": "4.1.11",
98
+ "eslint-plugin-format": "^1.4.0",
99
+ "eslint-plugin-vue": "^9.17.0",
100
+ "lefthook": "^2.1.1",
101
+ "miniprogram-ci": "^2.1.26",
102
+ "postcss": "^8.5.6",
103
+ "sass": "^1.75.0",
104
+ "style-loader": "^3.3.4",
105
+ "tsconfig-paths-webpack-plugin": "^4.1.0",
106
+ "typescript": "^5.9.3",
107
+ "unocss": "0.58.9",
108
+ "unocss-preset-weapp": "0.58.8",
109
+ "unplugin-vue-components": "^0.26.0",
110
+ "vue-loader": "^17.4.2",
111
+ "webpack": "5.91.0"
112
+ }
113
+ }
@@ -0,0 +1,13 @@
1
+ diff --git a/dist/WeappCI.js b/dist/WeappCI.js
2
+ index 778b65b4f366611ed3c577d3d470da391c3ca879..f6049120970a60a1cd9bbc420a7b835ea2056a49 100644
3
+ --- a/dist/WeappCI.js
4
+ +++ b/dist/WeappCI.js
5
+ @@ -67,7 +67,7 @@ class WeappCI extends BaseCi_1.default {
6
+ printLog("error" /* processTypeEnum.ERROR */, '命令行工具路径不存在', cliPath);
7
+ }
8
+ printLog("start" /* processTypeEnum.START */, '微信开发者工具...', this.projectPath);
9
+ - shell.exec(`${cliPath} open --project ${this.projectPath}`);
10
+ + shell.exec(`"${cliPath}" open --project "${this.projectPath}"`, { encoding: 'utf8' });
11
+ }
12
+ async preview() {
13
+ const { chalk, printLog, processTypeEnum } = this.ctx.helper;
@@ -0,0 +1,2 @@
1
+ patchedDependencies:
2
+ '@tarojs/plugin-mini-ci': patches/@tarojs__plugin-mini-ci.patch
@@ -0,0 +1,16 @@
1
+ {
2
+ "miniprogramRoot": "./dist/weapp",
3
+ "projectname": "myApp",
4
+ "description": "vue-taro-eslint",
5
+ "appid": "wxac3f99d8814754aa",
6
+ "setting": {
7
+ "urlCheck": true,
8
+ "es6": false,
9
+ "enhance": false,
10
+ "compileHotReLoad": false,
11
+ "postcss": false,
12
+ "minified": false,
13
+ "minifyWXML": true
14
+ },
15
+ "compileType": "miniprogram"
16
+ }
@@ -0,0 +1,11 @@
1
+ export default defineAppConfig({
2
+ pages: [
3
+ 'pages/index/index'
4
+ ],
5
+ window: {
6
+ backgroundTextStyle: 'light',
7
+ navigationBarBackgroundColor: '#fff',
8
+ navigationBarTitleText: 'WeChat',
9
+ navigationBarTextStyle: 'black'
10
+ }
11
+ })
@@ -0,0 +1,14 @@
1
+ import { createApp } from 'vue'
2
+ import { setupStore } from './store'
3
+ import '@nutui/touch-emulator'
4
+ import 'uno.css'
5
+ import './app.css'
6
+
7
+ const App = createApp({
8
+ onShow(_options) {
9
+ },
10
+ })
11
+
12
+ setupStore(App)
13
+
14
+ export default App
@@ -0,0 +1,17 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
5
+ <meta content="width=device-width,initial-scale=1,user-scalable=no" name="viewport">
6
+ <meta name="apple-mobile-web-app-capable" content="yes">
7
+ <meta name="apple-touch-fullscreen" content="yes">
8
+ <meta name="format-detection" content="telephone=no,address=no">
9
+ <meta name="apple-mobile-web-app-status-bar-style" content="white">
10
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" >
11
+ <title>myApp</title>
12
+ <script><%= htmlWebpackPlugin.options.script %></script>
13
+ </head>
14
+ <body>
15
+ <div id="app"></div>
16
+ </body>
17
+ </html>
@@ -0,0 +1,3 @@
1
+ export default definePageConfig({
2
+ navigationBarTitleText: '首页'
3
+ })
@@ -0,0 +1,4 @@
1
+ .red {
2
+ color: #fff;
3
+ background-color: red;
4
+ }
@@ -0,0 +1,18 @@
1
+ <script lang="ts" setup>
2
+ import { ref } from 'vue'
3
+ import styles from './index.module.scss'
4
+
5
+ const msg = ref('Hello world')
6
+ </script>
7
+
8
+ <template>
9
+ <div class="index">
10
+ <div :class="styles.red">
11
+ {{ msg }}
12
+ </div>
13
+ <div class="flex-1 text-green">
14
+ 222
15
+ </div>
16
+ <nut-button>111</nut-button>
17
+ </div>
18
+ </template>
@@ -0,0 +1,10 @@
1
+ import type { App } from 'vue'
2
+ import { createPinia } from 'pinia'
3
+ import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
4
+
5
+ export const store = createPinia()
6
+ store.use(piniaPluginPersistedstate)
7
+
8
+ export function setupStore(app: App) {
9
+ app.use(store)
10
+ }
@@ -0,0 +1,15 @@
1
+ import { defineStore } from 'pinia'
2
+ import { ref } from 'vue'
3
+ import { TaroStorage } from '../taroStorage'
4
+
5
+ export const useUserStore = defineStore('user', () => {
6
+ const user = ref('1')
7
+
8
+ return {
9
+ user,
10
+ }
11
+ }, {
12
+ persist: {
13
+ storage: TaroStorage,
14
+ },
15
+ })
@@ -0,0 +1,7 @@
1
+ import Taro from '@tarojs/taro'
2
+
3
+ export const TaroStorage = {
4
+ getItem: (name: string) => Taro.getStorageSync(name),
5
+ setItem: (name: string, value: string) => Taro.setStorageSync(name, value),
6
+ removeItem: (name: string) => Taro.removeStorageSync(name),
7
+ }
@@ -0,0 +1,6 @@
1
+ import process from 'node:process'
2
+
3
+ export const envVar = {
4
+ apiApi: process.env.TARO_API_URL,
5
+ weappId: process.env.TARO_WEAPP_ID,
6
+ }
@@ -0,0 +1,192 @@
1
+ import type { TaroConfig } from '@alova/adapter-taro'
2
+ import type Taro from '@tarojs/taro'
3
+ import type {
4
+ AlovaGlobalCacheAdapter,
5
+ AlovaOptions,
6
+ AlovaRequestAdapter,
7
+ GlobalCacheConfig,
8
+ StatesExport,
9
+ StatesHook,
10
+ } from 'alova'
11
+ import type { FetchRequestInit } from 'alova/fetch'
12
+ import { createAlova } from 'alova'
13
+ import adapterFetch from 'alova/fetch'
14
+ import { deepMergeObject, isReadableStream } from './utils'
15
+
16
+ // ---- Taro 适配器的响应类型 ----
17
+ type TaroResponse
18
+ = | Taro.request.SuccessCallbackResult<any>
19
+ | Taro.uploadFile.SuccessCallbackResult
20
+ | Taro.downloadFile.FileSuccessCallbackResult
21
+
22
+ type TaroResponseHeader = Taro.request.SuccessCallbackResult<any>['header']
23
+
24
+ // ---- 支持的适配器联合类型 ----
25
+ type SupportedRequestConfig = TaroConfig | FetchRequestInit
26
+ type SupportedResponse = TaroResponse | Response
27
+ type SupportedResponseHeader = TaroResponseHeader | Headers
28
+
29
+ interface StatusMap {
30
+ success?: number
31
+ unAuthorized?: number
32
+ }
33
+
34
+ interface CodeMap {
35
+ success?: number[]
36
+ unAuthorized?: number[]
37
+ }
38
+
39
+ export interface BaseRequestOption<
40
+ RC extends SupportedRequestConfig = SupportedRequestConfig,
41
+ RE extends SupportedResponse = SupportedResponse,
42
+ RH extends SupportedResponseHeader = SupportedResponseHeader,
43
+ SE extends StatesExport<any> = StatesExport<any>,
44
+ > {
45
+ baseUrl?: string
46
+ timeout?: number
47
+ commonHeaders?: Record<string, string | (() => string)>
48
+ statusMap?: StatusMap
49
+ isWrapped?: boolean
50
+ cacheFor?: GlobalCacheConfig<any>
51
+ cacheLogger?: boolean
52
+ codeMap?: CodeMap
53
+ responseDataKey?: string
54
+ responseMessageKey?: string
55
+ isTransformResponse?: boolean
56
+ isShowSuccessMessage?: boolean
57
+ successDefaultMessage?: string
58
+ isShowErrorMessage?: boolean
59
+ errorDefaultMessage?: string
60
+ statesHook?: StatesHook<SE>
61
+ successMessageFunc?: (message: string) => void
62
+ errorMessageFunc?: (message: string) => void
63
+ unAuthorizedResponseFunc?: () => void
64
+ requestAdapter?: AlovaRequestAdapter<RC, RE, RH>
65
+ storageAdapter?: AlovaGlobalCacheAdapter
66
+ }
67
+
68
+ /** method.meta 中可按请求覆盖的字段 */
69
+ export interface RequestMeta {
70
+ isTransformResponse?: boolean
71
+ isShowSuccessMessage?: boolean
72
+ isShowErrorMessage?: boolean
73
+ }
74
+
75
+ function getMetaFlag(meta: Record<string, any> | undefined, key: string, fallback: boolean): boolean {
76
+ if (meta && typeof meta[key] === 'boolean')
77
+ return meta[key]
78
+ return fallback
79
+ }
80
+
81
+ export function createInstance<
82
+ RC extends SupportedRequestConfig = SupportedRequestConfig,
83
+ RE extends SupportedResponse = SupportedResponse,
84
+ RH extends SupportedResponseHeader = SupportedResponseHeader,
85
+ SE extends StatesExport<any> = StatesExport<any>,
86
+ >(option: BaseRequestOption<RC, RE, RH, SE>) {
87
+ const defaultOption: BaseRequestOption = {
88
+ baseUrl: '/',
89
+ timeout: 0,
90
+ statusMap: { success: 200, unAuthorized: 401 },
91
+ isWrapped: true,
92
+ cacheFor: null,
93
+ cacheLogger: true,
94
+ codeMap: { success: [200], unAuthorized: [401] },
95
+ responseDataKey: 'data',
96
+ responseMessageKey: 'message',
97
+ isTransformResponse: true,
98
+ isShowSuccessMessage: false,
99
+ successDefaultMessage: '操作成功',
100
+ isShowErrorMessage: true,
101
+ errorDefaultMessage: '服务异常',
102
+ requestAdapter: adapterFetch() as AlovaRequestAdapter<any, any, any>,
103
+ }
104
+
105
+ const config = deepMergeObject(defaultOption, option) as Required<
106
+ Pick<BaseRequestOption, 'statusMap' | 'codeMap' | 'responseDataKey' | 'responseMessageKey'>
107
+ > & BaseRequestOption<RC, RE, RH, SE>
108
+
109
+ const alovaOptions: AlovaOptions<{
110
+ Responded: any
111
+ Transformed: any
112
+ RequestConfig: RC
113
+ Response: RE
114
+ ResponseHeader: RH
115
+ L1Cache: AlovaGlobalCacheAdapter
116
+ L2Cache: AlovaGlobalCacheAdapter
117
+ StatesExport: SE
118
+ }> = {
119
+ baseURL: config.baseUrl,
120
+ timeout: config.timeout,
121
+ cacheFor: config.cacheFor as any,
122
+ cacheLogger: config.cacheLogger,
123
+ statesHook: config.statesHook,
124
+ l2Cache: config.storageAdapter,
125
+ requestAdapter: config.requestAdapter!,
126
+ beforeRequest: async (method) => {
127
+ for (const [key, value] of Object.entries(config.commonHeaders ?? {})) {
128
+ method.config.headers[key] = typeof value === 'function' ? value() : value
129
+ }
130
+ },
131
+ responded: {
132
+ onSuccess: async (response, method) => {
133
+ const meta = method.meta as Record<string, any> | undefined
134
+ const shouldTransform = getMetaFlag(meta, 'isTransformResponse', config.isTransformResponse ?? true)
135
+ const showSuccess = getMetaFlag(meta, 'isShowSuccessMessage', config.isShowSuccessMessage ?? false)
136
+ const showError = getMetaFlag(meta, 'isShowErrorMessage', config.isShowErrorMessage ?? true)
137
+
138
+ if (!shouldTransform)
139
+ return response
140
+
141
+ // 兼容 fetch (status) 和 Taro (statusCode)
142
+ const status = (response as any).statusCode ?? (response as any).status
143
+ // 兼容 fetch (body 是 ReadableStream) 和 Taro (data 直接可用)
144
+ const data
145
+ = (response as any)?.body && isReadableStream((response as any).body)
146
+ ? await (response as Response).json()
147
+ : (response as any).data ?? response
148
+
149
+ if (status !== config.statusMap.success) {
150
+ if (config.statusMap.unAuthorized === status)
151
+ config.unAuthorizedResponseFunc?.()
152
+ if (showError)
153
+ config.errorMessageFunc?.(config.errorDefaultMessage ?? '服务异常')
154
+ return Promise.reject(response)
155
+ }
156
+
157
+ if (!config.isWrapped) {
158
+ if (showSuccess)
159
+ config.successMessageFunc?.(config.successDefaultMessage ?? '操作成功')
160
+ return data
161
+ }
162
+
163
+ const code = data?.code
164
+ const responseData = data?.[config.responseDataKey]
165
+ const responseMessage = data?.[config.responseMessageKey]
166
+
167
+ if (!config.codeMap.success?.includes(+code)) {
168
+ if (config.codeMap.unAuthorized?.includes(+code)) {
169
+ config.unAuthorizedResponseFunc?.()
170
+ return Promise.reject(response)
171
+ }
172
+ if (showError)
173
+ config.errorMessageFunc?.(responseMessage ?? config.errorDefaultMessage ?? '服务异常')
174
+ return Promise.reject(response)
175
+ }
176
+
177
+ if (showSuccess)
178
+ config.successMessageFunc?.(responseMessage ?? config.successDefaultMessage)
179
+ return responseData
180
+ },
181
+ onError: (error, method) => {
182
+ const meta = method.meta as Record<string, any> | undefined
183
+ const showError = getMetaFlag(meta, 'isShowErrorMessage', config.isShowErrorMessage ?? true)
184
+ if (showError)
185
+ config.errorMessageFunc?.(config.errorDefaultMessage ?? error.message)
186
+ return Promise.reject(error)
187
+ },
188
+ },
189
+ }
190
+
191
+ return createAlova(alovaOptions)
192
+ }
@@ -0,0 +1,30 @@
1
+ export function deepMergeObject<T = any>(source: T, target: Partial<T>): T {
2
+ const isObject = (obj: any): obj is Record<string, any> =>
3
+ obj && typeof obj === 'object' && !Array.isArray(obj)
4
+
5
+ const merge = (src: any, tgt: any): any => {
6
+ const result = { ...src }
7
+ if (isObject(result) && isObject(tgt)) {
8
+ Object.keys(tgt).forEach((key) => {
9
+ if (isObject(tgt[key])) {
10
+ result[key] = merge(result[key] || {}, tgt[key])
11
+ }
12
+ else {
13
+ result[key] = tgt[key]
14
+ }
15
+ })
16
+ }
17
+ return result
18
+ }
19
+
20
+ return merge(source, target)
21
+ }
22
+
23
+ /**
24
+ * 判断一个变量是不是可读流
25
+ */
26
+ export function isReadableStream(data: unknown): boolean {
27
+ if (typeof ReadableStream === 'undefined')
28
+ return false
29
+ return data instanceof ReadableStream
30
+ }
@@ -0,0 +1,44 @@
1
+ import type { TaroConfig } from '@alova/adapter-taro'
2
+ import type { VueHookExportType } from 'alova/vue'
3
+ import AdapterTaroVue from '@alova/adapter-taro/vue'
4
+ import Taro from '@tarojs/taro'
5
+ import { envVar } from '@/utils/env'
6
+ import { createInstance } from './core'
7
+
8
+ type TaroResponse
9
+ = | Taro.request.SuccessCallbackResult<any>
10
+ | Taro.uploadFile.SuccessCallbackResult
11
+ | Taro.downloadFile.FileSuccessCallbackResult
12
+
13
+ type TaroResponseHeader = Taro.request.SuccessCallbackResult<any>['header']
14
+
15
+ const taroAdapter = AdapterTaroVue()
16
+
17
+ const alovaRequest = createInstance<
18
+ TaroConfig,
19
+ TaroResponse,
20
+ TaroResponseHeader,
21
+ VueHookExportType<unknown>
22
+ >({
23
+ baseUrl: `${envVar.apiApi}`,
24
+ statusMap: { success: 200, unAuthorized: 401 },
25
+ codeMap: { success: [200] },
26
+ responseDataKey: 'data',
27
+ responseMessageKey: 'msg',
28
+ commonHeaders: {},
29
+ successMessageFunc: (msg) => {
30
+ Taro.showToast({ title: msg })
31
+ },
32
+ errorMessageFunc: (msg) => {
33
+ Taro.showToast({ title: msg, icon: 'error' })
34
+ },
35
+ unAuthorizedResponseFunc: () => {
36
+ Taro.showToast({ title: '登录过期或未登录' })
37
+ Taro.navigateTo({ url: '/pages/login/index' })
38
+ },
39
+ statesHook: taroAdapter.statesHook,
40
+ requestAdapter: taroAdapter.requestAdapter,
41
+ storageAdapter: taroAdapter.storageAdapter,
42
+ })
43
+
44
+ export default alovaRequest
@@ -0,0 +1,30 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2017",
4
+ "jsx": "preserve",
5
+ "experimentalDecorators": true,
6
+ "rootDir": ".",
7
+ "module": "commonjs",
8
+ "moduleResolution": "node",
9
+ "paths": {
10
+ // TS5090 leading './'
11
+ "@/*": ["./src/*"]
12
+ },
13
+ "resolveJsonModule": true,
14
+ "typeRoots": [
15
+ "node_modules/@types"
16
+ ],
17
+ "allowJs": true,
18
+ "strictNullChecks": true,
19
+ "noImplicitAny": false,
20
+ "noUnusedLocals": true,
21
+ "noUnusedParameters": true,
22
+ "outDir": "lib",
23
+ "preserveConstEnums": true,
24
+ "removeComments": false,
25
+ "sourceMap": true,
26
+ "allowSyntheticDefaultImports": true
27
+ },
28
+ "include": ["./src", "./types", "./config"],
29
+ "compileOnSave": false
30
+ }
@@ -0,0 +1,12 @@
1
+ /* eslint-disable */
2
+ /* prettier-ignore */
3
+ // @ts-nocheck
4
+ // Generated by unplugin-vue-components
5
+ // Read more: https://github.com/vuejs/core/pull/3399
6
+ export {}
7
+
8
+ declare module 'vue' {
9
+ export interface GlobalComponents {
10
+ NutButton: typeof import('@nutui/nutui-taro')['Button']
11
+ }
12
+ }
@@ -0,0 +1,31 @@
1
+ /// <reference types="@tarojs/taro" />
2
+
3
+ declare module '*.png';
4
+ declare module '*.gif';
5
+ declare module '*.jpg';
6
+ declare module '*.jpeg';
7
+ declare module '*.svg';
8
+ declare module '*.css';
9
+ declare module '*.less';
10
+ declare module '*.scss';
11
+ declare module '*.sass';
12
+ declare module '*.styl';
13
+
14
+ declare namespace NodeJS {
15
+ interface ProcessEnv {
16
+ /** NODE 内置环境变量, 会影响到最终构建生成产物 */
17
+ NODE_ENV: 'development' | 'production',
18
+ /** 当前构建的平台 */
19
+ TARO_ENV: 'weapp' | 'swan' | 'alipay' | 'h5' | 'rn' | 'tt' | 'qq' | 'jd' | 'harmony' | 'jdrn'
20
+ /**
21
+ * 当前构建的小程序 appid
22
+ * @description 若不同环境有不同的小程序,可通过在 env 文件中配置环境变量`TARO_APP_ID`来方便快速切换 appid, 而不必手动去修改 dist/project.config.json 文件
23
+ * @see https://taro-docs.jd.com/docs/next/env-mode-config#特殊环境变量-taro_app_id
24
+ */
25
+ TARO_APP_ID: string
26
+ }
27
+ }
28
+
29
+ declare module '@tarojs/components' {
30
+ export * from '@tarojs/components/types/index.vue3'
31
+ }
@@ -0,0 +1,10 @@
1
+ export {}
2
+
3
+ declare module 'vue' {
4
+ export interface GlobalComponents extends JSX.IntrinsicElements {
5
+ /** Note: Vue 在 runtime 中将 JSX.IntrinsicElements 通过 index signature 重复声明标签
6
+ * 这会导致插件无法正常跳转类型,可以手动覆盖声明标签活得更好的体验,参考如下:
7
+ * 'scroll-view': JSX.IntrinsicElements['scroll-view']
8
+ */
9
+ }
10
+ }
@@ -0,0 +1,38 @@
1
+ import process from 'node:process'
2
+ import { presetUno } from 'unocss'
3
+ import presetWeapp from 'unocss-preset-weapp'
4
+ import { extractorAttributify, transformerClass } from 'unocss-preset-weapp/transformer'
5
+
6
+ const { presetWeappAttributify, transformerAttributify } = extractorAttributify()
7
+
8
+ export default {
9
+ presets: [
10
+ // https://github.com/MellowCo/unocss-preset-weapp
11
+ presetWeapp(
12
+ // 以下配置为 webpack4 平台
13
+ // h5兼容设置,默认为 750 标准(designWidth: 750),webpack4 平台(taroWebpack: webpack4)
14
+ // 只开发小程序可删除
15
+ {
16
+ isH5: process.env.TARO_ENV === 'h5',
17
+ platform: 'taro',
18
+ },
19
+ ),
20
+ // attributify autocomplete
21
+ presetWeappAttributify(),
22
+ presetUno(),
23
+ ],
24
+ shortcuts: [
25
+ {
26
+ center: 'flex justify-center items-center',
27
+ },
28
+ ],
29
+
30
+ transformers: [
31
+ // https://github.com/MellowCo/unocss-preset-weapp/tree/main/src/transformer/transformerAttributify
32
+ // taro-react 不支持 Attributify Mode ,react不支持,react不支持,react不支持
33
+ transformerAttributify(),
34
+
35
+ // https://github.com/MellowCo/unocss-preset-weapp/tree/main/src/transformer/transformerClass
36
+ transformerClass(),
37
+ ],
38
+ }