create-miniprogram-scaffold 1.0.1 → 1.0.3
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/cli.js +1 -1
- package/package.json +3 -2
- package/templates/miniprogram/assets/tabbar/discover-active.png +0 -0
- package/templates/miniprogram/assets/tabbar/discover.png +0 -0
- package/templates/miniprogram/assets/tabbar/home-active.png +0 -0
- package/templates/miniprogram/assets/tabbar/home.png +0 -0
- package/templates/miniprogram/assets/tabbar/mine-active.png +0 -0
- package/templates/miniprogram/assets/tabbar/mine.png +0 -0
- package/templates/miniprogram/babel.config.js +10 -0
- package/templates/miniprogram/config/dev.ts +2 -0
- package/templates/miniprogram/config/index.ts +17 -0
- package/templates/miniprogram/config/prod.ts +2 -0
- package/templates/miniprogram/package.json +16 -0
- package/templates/miniprogram/project.config.json +31 -0
- package/templates/miniprogram/scripts/generate-tabbar-icons.js +9 -0
- package/templates/miniprogram/src/app.scss +9 -0
- package/templates/miniprogram/src/app.tsx +16 -0
- package/templates/miniprogram/src/layouts/FullscreenLayout/index.scss +2 -0
- package/templates/miniprogram/src/layouts/FullscreenLayout/index.tsx +6 -0
- package/templates/miniprogram/src/layouts/HeaderTabBarLayout/index.scss +11 -0
- package/templates/miniprogram/src/layouts/HeaderTabBarLayout/index.tsx +20 -0
- package/templates/miniprogram/src/layouts/README.md +7 -0
- package/templates/miniprogram/src/layouts/TabBarLayout/index.scss +1 -0
- package/templates/miniprogram/src/layouts/TabBarLayout/index.tsx +6 -0
- package/templates/miniprogram/src/layouts/index.ts +3 -0
- package/templates/miniprogram/src/pages/discover/index.config.ts +1 -0
- package/templates/miniprogram/src/pages/discover/index.scss +4 -0
- package/templates/miniprogram/src/pages/discover/index.tsx +6 -0
- package/templates/miniprogram/src/pages/home/index.config.ts +1 -0
- package/templates/miniprogram/src/pages/home/index.scss +6 -0
- package/templates/miniprogram/src/pages/home/index.tsx +17 -0
- package/templates/miniprogram/src/pages/mine/index.config.ts +1 -0
- package/templates/miniprogram/src/pages/mine/index.scss +4 -0
- package/templates/miniprogram/src/pages/mine/index.tsx +6 -0
- package/templates/miniprogram/src/pages/splash/index.config.ts +1 -0
- package/templates/miniprogram/src/pages/splash/index.scss +11 -0
- package/templates/miniprogram/src/pages/splash/index.tsx +15 -0
- package/templates/miniprogram/src/styles/variables.scss +41 -0
- package/templates/miniprogram/tsconfig.json +31 -0
- package/templates/miniprogram/types/global.d.ts +18 -0
- package/templates/server/.env.example +13 -0
- package/templates/server/Makefile +76 -0
- package/templates/server/README.md +134 -0
- package/templates/server/go.mod +25 -0
- package/templates/server/main.go +126 -0
package/bin/cli.js
CHANGED
|
@@ -27,7 +27,7 @@ program.name('create-mini-scaffold').description('Create Taro + Go mini program
|
|
|
27
27
|
]}, { type: 'input', name: 'port', message: 'Port?', default: cfg.port } ]); Object.assign(cfg, a); }
|
|
28
28
|
if (!['header-tabbar','tabbar','fullscreen','all'].includes(cfg.layout)) { console.error(chalk.red('Invalid layout')); process.exit(1); }
|
|
29
29
|
console.log(chalk.blue('\nCreating...'));
|
|
30
|
-
const tDir = path.join(__dirname, '..', '
|
|
30
|
+
const tDir = path.join(__dirname, '..', 'templates');
|
|
31
31
|
const mDir = path.join(dir, 'miniprogram');
|
|
32
32
|
await fs.ensureDir(mDir); await fs.ensureDir(path.join(dir, 'server'));
|
|
33
33
|
// Copy miniprogram (skip pages)
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-miniprogram-scaffold",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Create Taro + Go mini program projects",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/hk029/miniprogram-scaffold.git"
|
|
8
8
|
},
|
|
9
9
|
"main": "index.js",
|
|
10
|
+
"files": ["bin", "templates"],
|
|
10
11
|
"bin": {
|
|
11
|
-
"create-
|
|
12
|
+
"create-miniprogram-scaffold": "./bin/cli.js"
|
|
12
13
|
},
|
|
13
14
|
"scripts": {
|
|
14
15
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineConfig, type UserConfigExport } from '@tarojs/cli'
|
|
2
|
+
import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin'
|
|
3
|
+
import devConfig from './dev'
|
|
4
|
+
import prodConfig from './prod'
|
|
5
|
+
export default defineConfig(async (merge) => {
|
|
6
|
+
const base: UserConfigExport = {
|
|
7
|
+
projectName: 'mini-scaffold', designWidth() { return 750 },
|
|
8
|
+
deviceRatio: { 640: 2.34/2, 750: 1, 375: 2, 828: 1.81/2 },
|
|
9
|
+
sourceRoot: 'src', outputRoot: 'dist', plugins: [], framework: 'react', compiler: 'webpack5',
|
|
10
|
+
mini: {
|
|
11
|
+
postcss: { pxtransform: { enable: true, config: {} }, url: { enable: true, config: { limit: 1024 } }, cssModules: { enable: false, config: { namingPattern: 'module', generateScopedName: '[name]__[local]___[hash:base64:5]' } } },
|
|
12
|
+
miniCssExtractPluginOption: { ignoreOrder: true },
|
|
13
|
+
webpackChain(chain) { chain.resolve.plugin('tsconfig-paths').use(TsconfigPathsPlugin) }
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return process.env.NODE_ENV === 'development' ? merge({}, base, devConfig) : merge({}, base, prodConfig)
|
|
17
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mini-scaffold-miniprogram", "version": "1.0.0", "private": true, "description": "Taro + Go mini program",
|
|
3
|
+
"scripts": { "dev:weapp": "taro build --type weapp --watch", "build:weapp": "taro build --type weapp", "dev:h5": "taro build --type h5 --watch", "build:h5": "taro build --type h5" },
|
|
4
|
+
"browserslist": ["last 3 versions", "Android >= 4.1", "ios >= 8"],
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@babel/runtime": "^7.21.5", "@tarojs/components": "3.6.31", "@tarojs/helper": "3.6.31",
|
|
7
|
+
"@tarojs/plugin-framework-react": "3.6.31", "@tarojs/plugin-platform-weapp": "3.6.31",
|
|
8
|
+
"@tarojs/react": "3.6.31", "@tarojs/runtime": "3.6.31", "@tarojs/shared": "3.6.31",
|
|
9
|
+
"@tarojs/taro": "3.6.31", "@tarojs/taro-loader": "3.6.31", "react": "^18.0.0"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@babel/core": "^7.21.8", "@tarojs/cli": "3.6.31", "@tarojs/webpack5-runner": "3.6.31",
|
|
13
|
+
"@types/react": "^18.0.0", "babel-preset-taro": "3.6.31", "tsconfig-paths-webpack-plugin": "^4.0.1",
|
|
14
|
+
"typescript": "^5.1.0", "webpack": "5.88.2"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"miniprogramRoot": "dist/",
|
|
3
|
+
"projectname": "mini-scaffold",
|
|
4
|
+
"description": "Taro + Go 小程序脚手架",
|
|
5
|
+
"appid": "touristappid",
|
|
6
|
+
"setting": {
|
|
7
|
+
"urlCheck": true,
|
|
8
|
+
"es6": false,
|
|
9
|
+
"enhance": false,
|
|
10
|
+
"compileHotReLoad": false,
|
|
11
|
+
"postcss": false,
|
|
12
|
+
"minified": false,
|
|
13
|
+
"newFeature": true,
|
|
14
|
+
"coverView": true,
|
|
15
|
+
"nodeModules": false,
|
|
16
|
+
"autoAudits": false,
|
|
17
|
+
"showShadowRootInWxmlPanel": true,
|
|
18
|
+
"scopeDataCheck": false,
|
|
19
|
+
"uglifyFileName": false,
|
|
20
|
+
"checkInvalidKey": true,
|
|
21
|
+
"checkSiteMap": true,
|
|
22
|
+
"uploadWithSourceMap": true,
|
|
23
|
+
"babelSetting": {
|
|
24
|
+
"ignore": [],
|
|
25
|
+
"disablePlugins": [],
|
|
26
|
+
"outputPath": ""
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"compileType": "miniprogram",
|
|
30
|
+
"condition": {}
|
|
31
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const fs=require('fs'),path=require('path'),zlib=require('zlib')
|
|
2
|
+
const D=path.join(__dirname,'..','assets','tabbar'); fs.mkdirSync(D,{recursive:true})
|
|
3
|
+
function crc(b){let c=0xFFFFFFFF;for(let i=0;i<b.length;i++){c^=b[i];for(let j=0;j<8;j++)c=(c>>>1)^(c&1?0xEDB88320:0)}return(c^0xFFFFFFFF)>>>0}
|
|
4
|
+
function mk(t,d){const l=Buffer.alloc(4);l.writeUInt32BE(d.length,0);const tp=Buffer.from(t,'ascii');const cr=Buffer.alloc(4);cr.writeUInt32BE(crc(Buffer.concat([tp,d])),0);return Buffer.concat([l,tp,d,cr])}
|
|
5
|
+
function png(w,h,r,g,b){const p=[];for(let y=0;y<h;y++){p.push(0);for(let x=0;x<w;x++){Math.sqrt((x-32)**2+(y-32)**2)<=28?p.push(r,g,b):p.push(255,255,255)}}
|
|
6
|
+
return Buffer.concat([Buffer.from([137,80,78,71,13,10,26,10]),mk('IHDR',Buffer.from([0,0,0,w,0,0,0,h,8,2,0,0,0])),mk('IDAT',zlib.deflateSync(Buffer.from(p))),mk('IEND',Buffer.alloc(0))])}
|
|
7
|
+
const I=[{n:'home',c:'999999',a:'1890ff'},{n:'discover',c:'999999',a:'1890ff'},{n:'mine',c:'999999',a:'1890ff'}]
|
|
8
|
+
for(const{n,c,a}of I){const cr=h=>[parseInt(h.slice(1,3),16),parseInt(h.slice(3,5),16),parseInt(h.slice(5,7),16)];const[r1,g1,b1]=cr(c),[r2,g2,b2]=cr(a)
|
|
9
|
+
fs.writeFileSync(path.join(D,`${n}.png`),png(81,81,r1,g1,b1));fs.writeFileSync(path.join(D,`${n}-active.png`),png(81,81,r2,g2,b2));console.log(`✓ ${n}`)}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Component, PropsWithChildren } from 'react'
|
|
2
|
+
import './app.scss'
|
|
3
|
+
|
|
4
|
+
class App extends Component<PropsWithChildren> {
|
|
5
|
+
componentDidMount() {}
|
|
6
|
+
|
|
7
|
+
componentDidShow() {}
|
|
8
|
+
|
|
9
|
+
componentDidHide() {}
|
|
10
|
+
|
|
11
|
+
render() {
|
|
12
|
+
return this.props.children
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default App
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ReactNode } from 'react'
|
|
2
|
+
import { View } from '@tarojs/components'
|
|
3
|
+
import './index.scss'
|
|
4
|
+
export default function FullscreenLayout({ children, className = '', safeArea = true }: { children: ReactNode; className?: string; safeArea?: boolean }) {
|
|
5
|
+
return <View className={`fullscreen-layout ${safeArea ? 'fullscreen-layout--safe' : ''} ${className}`}>{children}</View>
|
|
6
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
@import '../../styles/variables.scss';
|
|
2
|
+
.header-tabbar-layout { width: 100%; min-height: 100vh; display: flex; flex-direction: column; background-color: $bg-color;
|
|
3
|
+
&__header { position: sticky; top: 0; z-index: 100; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 0 0 $border-radius-lg $border-radius-lg; overflow: hidden; }
|
|
4
|
+
&__header-content { display: flex; align-items: center; justify-content: space-between; padding: $spacing-md $spacing-lg; }
|
|
5
|
+
&__title-area { flex: 1; min-width: 0; }
|
|
6
|
+
&__title { display: block; font-size: var(--fs-xxl); font-weight: 800; color: $text-color-inverse; line-height: 1.2; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
7
|
+
&__subtitle { display: block; margin-top: $spacing-xs; font-size: var(--fs-sm); color: rgba(255,255,255,0.8); }
|
|
8
|
+
&__action { flex-shrink: 0; margin-left: $spacing-md; display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; }
|
|
9
|
+
&__search { padding: 0 $spacing-lg $spacing-md; }
|
|
10
|
+
&__search-input { width: 100%; height: 64rpx; padding: 0 $spacing-lg; background: rgba(255,255,255,0.9); border-radius: 32rpx; font-size: var(--fs-sm); color: $text-color; }
|
|
11
|
+
&__body { flex: 1; min-height: 0; display: flex; flex-direction: column; padding: $spacing-lg; } }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ReactNode } from 'react'
|
|
2
|
+
import { View, Text, Input } from '@tarojs/components'
|
|
3
|
+
import Taro from '@tarojs/taro'
|
|
4
|
+
import './index.scss'
|
|
5
|
+
export default function HeaderTabBarLayout({ title, subtitle, showSearch = false, onSearch, rightAction, children, className = '' }: { title: string; subtitle?: string; showSearch?: boolean; onSearch?: (k: string) => void; rightAction?: ReactNode; children: ReactNode; className?: string }) {
|
|
6
|
+
const sb = Taro.getSystemInfoSync().statusBarHeight || 20
|
|
7
|
+
return <View className={`header-tabbar-layout ${className}`}>
|
|
8
|
+
<View className='header-tabbar-layout__header' style={{ paddingTop: `${sb}px` }}>
|
|
9
|
+
<View className='header-tabbar-layout__header-content'>
|
|
10
|
+
<View className='header-tabbar-layout__title-area'>
|
|
11
|
+
<Text className='header-tabbar-layout__title'>{title}</Text>
|
|
12
|
+
{subtitle && <Text className='header-tabbar-layout__subtitle'>{subtitle}</Text>}
|
|
13
|
+
</View>
|
|
14
|
+
{rightAction && <View className='header-tabbar-layout__action'>{rightAction}</View>}
|
|
15
|
+
</View>
|
|
16
|
+
{showSearch && <View className='header-tabbar-layout__search'><Input className='header-tabbar-layout__search-input' type='text' placeholder='搜索...' confirmType='search' onConfirm={(e) => onSearch?.(e.detail.value)} /></View>}
|
|
17
|
+
</View>
|
|
18
|
+
<View className='header-tabbar-layout__body'>{children}</View>
|
|
19
|
+
</View>
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.tabbar-layout { width: 100%; min-height: 100vh; display: flex; flex-direction: column; background-color: #f5f5f5; }
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ReactNode } from 'react'
|
|
2
|
+
import { View } from '@tarojs/components'
|
|
3
|
+
import './index.scss'
|
|
4
|
+
export default function TabBarLayout({ children, className = '' }: { children: ReactNode; className?: string }) {
|
|
5
|
+
return <View className={`tabbar-layout ${className}`}>{children}</View>
|
|
6
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default definePageConfig({ navigationBarTitleText: '发现' })
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
@import '../../styles/variables.scss';
|
|
2
|
+
.discover { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: $spacing-xl;
|
|
3
|
+
&__title { display: block; font-size: var(--fs-xxl); font-weight: 700; color: $text-color; margin-bottom: $spacing-md; }
|
|
4
|
+
&__desc { display: block; font-size: var(--fs-sm); color: $text-color-secondary; } }
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { View, Text } from '@tarojs/components'
|
|
2
|
+
import { TabBarLayout } from '@/layouts'
|
|
3
|
+
import './index.scss'
|
|
4
|
+
export default function DiscoverPage() {
|
|
5
|
+
return <TabBarLayout><View className='discover'><Text className='discover__title'>发现</Text><Text className='discover__desc'>标准 TabBar 布局</Text></View></TabBarLayout>
|
|
6
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default definePageConfig({ navigationStyle: 'custom' })
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
@import '../../styles/variables.scss';
|
|
2
|
+
.home { flex: 1;
|
|
3
|
+
&__card { background: $bg-color-white; border-radius: $border-radius-lg; padding: $spacing-xl; box-shadow: $shadow-base; }
|
|
4
|
+
&__card-title { display: block; font-size: var(--fs-lg); font-weight: 700; color: $text-color; margin-bottom: $spacing-md; padding-bottom: $spacing-md; border-bottom: 1px solid $border-color-light; }
|
|
5
|
+
&__card-body { display: block; font-size: var(--fs-base); color: $text-color-secondary; margin-bottom: $spacing-xl; text-align: center; padding: $spacing-xl 0; }
|
|
6
|
+
&__btn { width: 100%; height: 80rpx; line-height: 80rpx; background: $primary-color; color: $text-color-inverse; font-size: var(--fs-base); border-radius: $border-radius-base; border: none; } }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react'
|
|
2
|
+
import { View, Text, Button } from '@tarojs/components'
|
|
3
|
+
import Taro from '@tarojs/taro'
|
|
4
|
+
import { HeaderTabBarLayout } from '@/layouts'
|
|
5
|
+
import './index.scss'
|
|
6
|
+
export default function HomePage() {
|
|
7
|
+
const [g, setG] = useState(''), [loading, setLoading] = useState(false)
|
|
8
|
+
const fetch = async () => { setLoading(true); try { const r = await Taro.request({ url: 'http://localhost:8080/api/hello' }); const d = r.data as any; if (d.code === 0) setG(d.data.greeting) } catch { Taro.showToast({ title: '网络错误', icon: 'none' }) } finally { setLoading(false) } }
|
|
9
|
+
useEffect(() => { fetch() }, [])
|
|
10
|
+
return <HeaderTabBarLayout title='首页' subtitle='Taro + Go 脚手架' showSearch onSearch={(k) => Taro.showToast({ title: `搜索: ${k}`, icon: 'none' })}>
|
|
11
|
+
<View className='home'><View className='home__card'>
|
|
12
|
+
<Text className='home__card-title'>Hello World</Text>
|
|
13
|
+
<Text className='home__card-body'>{loading ? '加载中...' : g || '暂无数据'}</Text>
|
|
14
|
+
<Button className='home__btn' onClick={fetch} loading={loading}>刷新</Button>
|
|
15
|
+
</View></View>
|
|
16
|
+
</HeaderTabBarLayout>
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default definePageConfig({ navigationBarTitleText: '我的' })
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
@import '../../styles/variables.scss';
|
|
2
|
+
.mine { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: $spacing-xl;
|
|
3
|
+
&__title { display: block; font-size: var(--fs-xxl); font-weight: 700; color: $text-color; margin-bottom: $spacing-md; }
|
|
4
|
+
&__desc { display: block; font-size: var(--fs-sm); color: $text-color-secondary; } }
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { View, Text } from '@tarojs/components'
|
|
2
|
+
import { TabBarLayout } from '@/layouts'
|
|
3
|
+
import './index.scss'
|
|
4
|
+
export default function MinePage() {
|
|
5
|
+
return <TabBarLayout><View className='mine'><Text className='mine__title'>我的</Text><Text className='mine__desc'>个人中心</Text></View></TabBarLayout>
|
|
6
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default definePageConfig({ navigationStyle: 'custom', backgroundColor: '#000000' })
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
@import '../../styles/variables.scss';
|
|
2
|
+
.splash { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); display: flex; flex-direction: column; align-items: center; justify-content: space-between;
|
|
3
|
+
&__content { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: $spacing-xl; }
|
|
4
|
+
&__logo { width: 160rpx; height: 160rpx; border-radius: 50%; background: rgba(255,255,255,0.2); display: flex; align-items: center; justify-content: center; margin-bottom: $spacing-xl; }
|
|
5
|
+
&__logo-text { font-size: 56rpx; font-weight: 800; color: #fff; }
|
|
6
|
+
&__title { display: block; font-size: var(--fs-hero); font-weight: 800; color: #fff; margin-bottom: $spacing-md; }
|
|
7
|
+
&__subtitle { display: block; font-size: var(--fs-base); color: rgba(255,255,255,0.8); margin-bottom: 48px; }
|
|
8
|
+
&__btn { width: 400rpx; height: 96rpx; border-radius: 48rpx; background: #fff; display: flex; align-items: center; justify-content: center; }
|
|
9
|
+
&__btn-text { font-size: var(--fs-lg); font-weight: 600; color: #667eea; }
|
|
10
|
+
&__footer { padding-bottom: 80rpx; }
|
|
11
|
+
&__footer-text { font-size: var(--fs-xs); color: rgba(255,255,255,0.5); } }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { View, Text } from '@tarojs/components'
|
|
2
|
+
import Taro from '@tarojs/taro'
|
|
3
|
+
import { FullscreenLayout } from '@/layouts'
|
|
4
|
+
import './index.scss'
|
|
5
|
+
export default function SplashPage() {
|
|
6
|
+
return <FullscreenLayout safeArea={false} className='splash'>
|
|
7
|
+
<View className='splash__content'>
|
|
8
|
+
<View className='splash__logo'><Text className='splash__logo-text'>MS</Text></View>
|
|
9
|
+
<Text className='splash__title'>Mini Scaffold</Text>
|
|
10
|
+
<Text className='splash__subtitle'>Taro + Go 小程序脚手架</Text>
|
|
11
|
+
<View className='splash__btn' onClick={() => Taro.switchTab({ url: '/pages/home/index' })}><Text className='splash__btn-text'>进入</Text></View>
|
|
12
|
+
</View>
|
|
13
|
+
<View className='splash__footer'><Text className='splash__footer-text'>全屏沉浸式布局</Text></View>
|
|
14
|
+
</FullscreenLayout>
|
|
15
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Colors
|
|
2
|
+
$primary-color: #1890ff;
|
|
3
|
+
$success-color: #52c41a;
|
|
4
|
+
$warning-color: #faad14;
|
|
5
|
+
$error-color: #f5222d;
|
|
6
|
+
|
|
7
|
+
// Text colors
|
|
8
|
+
$text-color: #333333;
|
|
9
|
+
$text-color-secondary: #666666;
|
|
10
|
+
$text-color-inverse: #ffffff;
|
|
11
|
+
|
|
12
|
+
// Background colors
|
|
13
|
+
$bg-color: #f5f5f5;
|
|
14
|
+
$bg-color-white: #ffffff;
|
|
15
|
+
|
|
16
|
+
// Border colors
|
|
17
|
+
$border-color: #d9d9d9;
|
|
18
|
+
$border-color-light: #e8e8e8;
|
|
19
|
+
|
|
20
|
+
// Font sizes
|
|
21
|
+
$font-size-sm: 12px;
|
|
22
|
+
$font-size-base: 14px;
|
|
23
|
+
$font-size-lg: 16px;
|
|
24
|
+
$font-size-xl: 18px;
|
|
25
|
+
|
|
26
|
+
// Spacing
|
|
27
|
+
$spacing-xs: 4px;
|
|
28
|
+
$spacing-sm: 8px;
|
|
29
|
+
$spacing-md: 12px;
|
|
30
|
+
$spacing-lg: 16px;
|
|
31
|
+
$spacing-xl: 24px;
|
|
32
|
+
|
|
33
|
+
// Border radius
|
|
34
|
+
$border-radius-sm: 2px;
|
|
35
|
+
$border-radius-base: 4px;
|
|
36
|
+
$border-radius-lg: 8px;
|
|
37
|
+
|
|
38
|
+
// Shadows
|
|
39
|
+
$shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.03), 0 1px 6px -1px rgba(0, 0, 0, 0.02), 0 2px 4px 0 rgba(0, 0, 0, 0.02);
|
|
40
|
+
$shadow-base: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
|
|
41
|
+
$shadow-lg: 0 6px 16px -8px rgba(0, 0, 0, 0.08), 0 9px 28px 0 rgba(0, 0, 0, 0.05), 0 12px 48px 16px rgba(0, 0, 0, 0.03);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es2017",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"removeComments": false,
|
|
6
|
+
"preserveConstEnums": true,
|
|
7
|
+
"moduleResolution": "node",
|
|
8
|
+
"experimentalDecorators": true,
|
|
9
|
+
"noImplicitAny": false,
|
|
10
|
+
"allowSyntheticDefaultImports": true,
|
|
11
|
+
"outDir": "lib",
|
|
12
|
+
"noUnusedLocals": true,
|
|
13
|
+
"noUnusedParameters": true,
|
|
14
|
+
"strictNullChecks": true,
|
|
15
|
+
"sourceMap": true,
|
|
16
|
+
"rootDir": ".",
|
|
17
|
+
"jsx": "react-jsx",
|
|
18
|
+
"allowJs": true,
|
|
19
|
+
"resolveJsonModule": true,
|
|
20
|
+
"typeRoots": [
|
|
21
|
+
"node_modules/@types",
|
|
22
|
+
"global.d.ts"
|
|
23
|
+
],
|
|
24
|
+
"paths": {
|
|
25
|
+
"@/*": ["./src/*"]
|
|
26
|
+
},
|
|
27
|
+
"baseUrl": "."
|
|
28
|
+
},
|
|
29
|
+
"include": ["src", "types", "config"],
|
|
30
|
+
"compileOnSave": false
|
|
31
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
TARO_ENV: 'weapp' | 'swan' | 'alipay' | 'h5' | 'rn' | 'tt' | 'quickapp' | 'qq' | 'jd' | 'harmony-hybrid'
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Server configuration
|
|
2
|
+
PORT=8080
|
|
3
|
+
|
|
4
|
+
# Application configuration
|
|
5
|
+
APP_NAME=Mini Scaffold API
|
|
6
|
+
APP_ENV=development
|
|
7
|
+
|
|
8
|
+
# Database configuration (example)
|
|
9
|
+
# DB_HOST=localhost
|
|
10
|
+
# DB_PORT=5432
|
|
11
|
+
# DB_USER=postgres
|
|
12
|
+
# DB_PASSWORD=password
|
|
13
|
+
# DB_NAME=mini_scaffold
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
.PHONY: build run clean test dev
|
|
2
|
+
|
|
3
|
+
# Variables
|
|
4
|
+
APP_NAME := server
|
|
5
|
+
BUILD_DIR := ./bin
|
|
6
|
+
GO := go
|
|
7
|
+
|
|
8
|
+
# Build the application
|
|
9
|
+
build:
|
|
10
|
+
@echo "Building $(APP_NAME)..."
|
|
11
|
+
@mkdir -p $(BUILD_DIR)
|
|
12
|
+
$(GO) build -o $(BUILD_DIR)/$(APP_NAME) main.go
|
|
13
|
+
@echo "Build complete: $(BUILD_DIR)/$(APP_NAME)"
|
|
14
|
+
|
|
15
|
+
# Run the application
|
|
16
|
+
run: build
|
|
17
|
+
@echo "Starting $(APP_NAME)..."
|
|
18
|
+
$(BUILD_DIR)/$(APP_NAME)
|
|
19
|
+
|
|
20
|
+
# Run in development mode with hot reload (requires air)
|
|
21
|
+
dev:
|
|
22
|
+
@echo "Starting development server..."
|
|
23
|
+
@which air > /dev/null 2>&1 || (echo "Installing air..." && go install github.com/cosmtrek/air@latest)
|
|
24
|
+
air
|
|
25
|
+
|
|
26
|
+
# Clean build artifacts
|
|
27
|
+
clean:
|
|
28
|
+
@echo "Cleaning build artifacts..."
|
|
29
|
+
@rm -rf $(BUILD_DIR)
|
|
30
|
+
@echo "Clean complete"
|
|
31
|
+
|
|
32
|
+
# Run tests
|
|
33
|
+
test:
|
|
34
|
+
@echo "Running tests..."
|
|
35
|
+
$(GO) test -v ./...
|
|
36
|
+
|
|
37
|
+
# Format code
|
|
38
|
+
fmt:
|
|
39
|
+
@echo "Formatting code..."
|
|
40
|
+
$(GO) fmt ./...
|
|
41
|
+
|
|
42
|
+
# Vet code
|
|
43
|
+
vet:
|
|
44
|
+
@echo "Vetting code..."
|
|
45
|
+
$(GO) vet ./...
|
|
46
|
+
|
|
47
|
+
# Lint code (requires golangci-lint)
|
|
48
|
+
lint:
|
|
49
|
+
@echo "Linting code..."
|
|
50
|
+
@which golangci-lint > /dev/null 2>&1 || (echo "Installing golangci-lint..." && go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest)
|
|
51
|
+
golangci-lint run
|
|
52
|
+
|
|
53
|
+
# Download dependencies
|
|
54
|
+
deps:
|
|
55
|
+
@echo "Downloading dependencies..."
|
|
56
|
+
$(GO) mod download
|
|
57
|
+
|
|
58
|
+
# Tidy dependencies
|
|
59
|
+
tidy:
|
|
60
|
+
@echo "Tidying dependencies..."
|
|
61
|
+
$(GO) mod tidy
|
|
62
|
+
|
|
63
|
+
# Show help
|
|
64
|
+
help:
|
|
65
|
+
@echo "Available targets:"
|
|
66
|
+
@echo " build - Build the application"
|
|
67
|
+
@echo " run - Build and run the application"
|
|
68
|
+
@echo " dev - Run in development mode with hot reload"
|
|
69
|
+
@echo " clean - Clean build artifacts"
|
|
70
|
+
@echo " test - Run tests"
|
|
71
|
+
@echo " fmt - Format code"
|
|
72
|
+
@echo " vet - Vet code"
|
|
73
|
+
@echo " lint - Lint code"
|
|
74
|
+
@echo " deps - Download dependencies"
|
|
75
|
+
@echo " tidy - Tidy dependencies"
|
|
76
|
+
@echo " help - Show this help"
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Mini Scaffold Server
|
|
2
|
+
|
|
3
|
+
A simple Go backend server built with Fiber framework.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Go 1.21 or higher
|
|
8
|
+
|
|
9
|
+
## Getting Started
|
|
10
|
+
|
|
11
|
+
### Install dependencies
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
go mod tidy
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Run the server
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Using make
|
|
21
|
+
make run
|
|
22
|
+
|
|
23
|
+
# Or directly
|
|
24
|
+
go run main.go
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Development mode
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Using make (requires air for hot reload)
|
|
31
|
+
make dev
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## API Endpoints
|
|
35
|
+
|
|
36
|
+
### Health Check
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
GET /api/health
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Response:
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"code": 200,
|
|
46
|
+
"message": "OK",
|
|
47
|
+
"data": {
|
|
48
|
+
"status": "healthy"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Hello World
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
GET /api/hello
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Response:
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"code": 200,
|
|
63
|
+
"message": "success",
|
|
64
|
+
"data": {
|
|
65
|
+
"greeting": "Hello, World! 来自 Go 后端",
|
|
66
|
+
"timestamp": "2024-01-01T00:00:00Z",
|
|
67
|
+
"version": "1.0.0"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Hello with Name
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
POST /api/hello
|
|
76
|
+
Content-Type: application/json
|
|
77
|
+
|
|
78
|
+
{
|
|
79
|
+
"name": "YourName"
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Response:
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"code": 200,
|
|
87
|
+
"message": "success",
|
|
88
|
+
"data": {
|
|
89
|
+
"greeting": "Hello, YourName! 来自 Go 后端",
|
|
90
|
+
"timestamp": "2024-01-01T00:00:00Z"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Configuration
|
|
96
|
+
|
|
97
|
+
The server can be configured using environment variables or a `.env` file:
|
|
98
|
+
|
|
99
|
+
- `PORT` - Server port (default: 8080)
|
|
100
|
+
- `APP_NAME` - Application name
|
|
101
|
+
- `APP_ENV` - Application environment (development/production)
|
|
102
|
+
|
|
103
|
+
## Project Structure
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
server/
|
|
107
|
+
├── main.go # Entry point
|
|
108
|
+
├── go.mod # Go module file
|
|
109
|
+
├── go.sum # Go dependencies checksum
|
|
110
|
+
├── .env # Environment variables
|
|
111
|
+
├── .env.example # Example environment variables
|
|
112
|
+
├── Makefile # Build and run commands
|
|
113
|
+
└── README.md # This file
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Building for Production
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# Build binary
|
|
120
|
+
make build
|
|
121
|
+
|
|
122
|
+
# Run binary
|
|
123
|
+
./bin/server
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Testing
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
make test
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
MIT
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module mini-scaffold-server
|
|
2
|
+
|
|
3
|
+
go 1.21
|
|
4
|
+
|
|
5
|
+
require (
|
|
6
|
+
github.com/gofiber/fiber/v2 v2.52.0
|
|
7
|
+
github.com/joho/godotenv v1.5.1
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
require (
|
|
11
|
+
github.com/andybalholm/brotli v1.0.5 // indirect
|
|
12
|
+
github.com/google/uuid v1.5.0 // indirect
|
|
13
|
+
github.com/klauspost/compress v1.17.4 // indirect
|
|
14
|
+
github.com/mattn/go-colorable v0.1.13 // indirect
|
|
15
|
+
github.com/mattn/go-isatty v0.0.20 // indirect
|
|
16
|
+
github.com/mattn/go-runewidth v0.0.15 // indirect
|
|
17
|
+
github.com/philhofer/fwd v1.1.2 // indirect
|
|
18
|
+
github.com/rivo/uniseg v0.4.4 // indirect
|
|
19
|
+
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
|
|
20
|
+
github.com/tinylib/msgp v1.1.9 // indirect
|
|
21
|
+
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
|
22
|
+
github.com/valyala/fasthttp v1.51.0 // indirect
|
|
23
|
+
github.com/valyala/tcplisten v1.0.0 // indirect
|
|
24
|
+
golang.org/x/sys v0.15.0 // indirect
|
|
25
|
+
)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"log"
|
|
5
|
+
"os"
|
|
6
|
+
|
|
7
|
+
"github.com/gofiber/fiber/v2"
|
|
8
|
+
"github.com/gofiber/fiber/v2/middleware/cors"
|
|
9
|
+
"github.com/gofiber/fiber/v2/middleware/logger"
|
|
10
|
+
"github.com/gofiber/fiber/v2/middleware/recover"
|
|
11
|
+
"github.com/joho/godotenv"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
func main() {
|
|
15
|
+
// Load .env file if it exists
|
|
16
|
+
if err := godotenv.Load(); err != nil {
|
|
17
|
+
log.Println("No .env file found, using default configuration")
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Get port from environment variable or use default
|
|
21
|
+
port := os.Getenv("PORT")
|
|
22
|
+
if port == "" {
|
|
23
|
+
port = "8080"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Create Fiber app
|
|
27
|
+
app := fiber.New(fiber.Config{
|
|
28
|
+
AppName: "Mini Scaffold API",
|
|
29
|
+
ServerHeader: "Mini Scaffold",
|
|
30
|
+
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
|
31
|
+
code := fiber.StatusInternalServerError
|
|
32
|
+
if e, ok := err.(*fiber.Error); ok {
|
|
33
|
+
code = e.Code
|
|
34
|
+
}
|
|
35
|
+
return c.Status(code).JSON(fiber.Map{
|
|
36
|
+
"code": code,
|
|
37
|
+
"message": err.Error(),
|
|
38
|
+
})
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
// Middleware
|
|
43
|
+
app.Use(recover.New())
|
|
44
|
+
app.Use(logger.New(logger.Config{
|
|
45
|
+
Format: "${time} ${method} ${path} ${status} ${latency}\n",
|
|
46
|
+
}))
|
|
47
|
+
app.Use(cors.New(cors.Config{
|
|
48
|
+
AllowOrigins: "*",
|
|
49
|
+
AllowMethods: "GET,POST,PUT,DELETE,OPTIONS",
|
|
50
|
+
AllowHeaders: "Origin,Content-Type,Accept,Authorization",
|
|
51
|
+
}))
|
|
52
|
+
|
|
53
|
+
// Routes
|
|
54
|
+
setupRoutes(app)
|
|
55
|
+
|
|
56
|
+
// Start server
|
|
57
|
+
log.Printf("Server starting on port %s", port)
|
|
58
|
+
if err := app.Listen(":" + port); err != nil {
|
|
59
|
+
log.Fatalf("Failed to start server: %v", err)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
func setupRoutes(app *fiber.App) {
|
|
64
|
+
// API group
|
|
65
|
+
api := app.Group("/api")
|
|
66
|
+
|
|
67
|
+
// Health check
|
|
68
|
+
api.Get("/health", func(c *fiber.Ctx) error {
|
|
69
|
+
return c.JSON(fiber.Map{
|
|
70
|
+
"code": 200,
|
|
71
|
+
"message": "OK",
|
|
72
|
+
"data": fiber.Map{
|
|
73
|
+
"status": "healthy",
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
// Hello world endpoint
|
|
79
|
+
api.Get("/hello", func(c *fiber.Ctx) error {
|
|
80
|
+
return c.JSON(fiber.Map{
|
|
81
|
+
"code": 200,
|
|
82
|
+
"message": "success",
|
|
83
|
+
"data": fiber.Map{
|
|
84
|
+
"greeting": "Hello, World! 来自 Go 后端",
|
|
85
|
+
"timestamp": "2024-01-01T00:00:00Z",
|
|
86
|
+
"version": "1.0.0",
|
|
87
|
+
},
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
// Example POST endpoint
|
|
92
|
+
api.Post("/hello", func(c *fiber.Ctx) error {
|
|
93
|
+
type Request struct {
|
|
94
|
+
Name string `json:"name"`
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
var req Request
|
|
98
|
+
if err := c.BodyParser(&req); err != nil {
|
|
99
|
+
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
100
|
+
"code": 400,
|
|
101
|
+
"message": "Invalid request body",
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if req.Name == "" {
|
|
106
|
+
req.Name = "World"
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return c.JSON(fiber.Map{
|
|
110
|
+
"code": 200,
|
|
111
|
+
"message": "success",
|
|
112
|
+
"data": fiber.Map{
|
|
113
|
+
"greeting": "Hello, " + req.Name + "! 来自 Go 后端",
|
|
114
|
+
"timestamp": "2024-01-01T00:00:00Z",
|
|
115
|
+
},
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
// Catch-all route for 404
|
|
120
|
+
app.Use(func(c *fiber.Ctx) error {
|
|
121
|
+
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
|
|
122
|
+
"code": 404,
|
|
123
|
+
"message": "Route not found",
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
}
|