@stdex/create 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +66 -2
- package/README_EN.md +67 -0
- package/package.json +39 -3
- package/src/eslint.config.js +2 -0
- package/src/index.js +232 -0
- package/templates/base/eslint.config.js +2 -0
- package/templates/base/index.js +1 -0
- package/templates/base/package.json +16 -0
- package/templates/miniprogram/README.md +27 -0
- package/templates/miniprogram/_gitignore +3 -0
- package/templates/miniprogram/dist/app.js +9 -0
- package/templates/miniprogram/dist/app.json +16 -0
- package/templates/miniprogram/dist/app.wxss +0 -0
- package/templates/miniprogram/dist/lib/app-data.js +51 -0
- package/templates/miniprogram/dist/pages/index/index.js +20 -0
- package/templates/miniprogram/dist/pages/index/index.json +3 -0
- package/templates/miniprogram/dist/pages/index/index.wxml +1 -0
- package/templates/miniprogram/dist/pages/index/index.wxss +11 -0
- package/templates/miniprogram/dist/sitemap.json +9 -0
- package/templates/miniprogram/eslint.config.cjs +25 -0
- package/templates/miniprogram/gulpfile.js +81 -0
- package/templates/miniprogram/package.json +22 -0
- package/templates/miniprogram/project.config.json +31 -0
- package/templates/miniprogram/project.private.config.json +8 -0
- package/templates/miniprogram/src/app.json +16 -0
- package/templates/miniprogram/src/app.scss +0 -0
- package/templates/miniprogram/src/app.ts +6 -0
- package/templates/miniprogram/src/lib/app-data.ts +46 -0
- package/templates/miniprogram/src/pages/index/index.json +3 -0
- package/templates/miniprogram/src/pages/index/index.scss +11 -0
- package/templates/miniprogram/src/pages/index/index.ts +13 -0
- package/templates/miniprogram/src/pages/index/index.wxml +1 -0
- package/templates/miniprogram/src/sitemap.json +9 -0
- package/templates/miniprogram/tsconfig.json +11 -0
- package/templates/miniprogram/typings/index.d.ts +5 -0
- package/templates/miniprogram/typings/types/index.d.ts +1 -0
- package/templates/miniprogram/typings/types/wx/index.d.ts +162 -0
- package/templates/miniprogram/typings/types/wx/lib.wx.api.d.ts +32387 -0
- package/templates/miniprogram/typings/types/wx/lib.wx.app.d.ts +400 -0
- package/templates/miniprogram/typings/types/wx/lib.wx.behavior.d.ts +68 -0
- package/templates/miniprogram/typings/types/wx/lib.wx.canvas.d.ts +2623 -0
- package/templates/miniprogram/typings/types/wx/lib.wx.cloud.d.ts +1016 -0
- package/templates/miniprogram/typings/types/wx/lib.wx.component.d.ts +700 -0
- package/templates/miniprogram/typings/types/wx/lib.wx.event.d.ts +1436 -0
- package/templates/miniprogram/typings/types/wx/lib.wx.page.d.ts +272 -0
- package/templates/miniprogram/typings/types/wx/lib.wx.phys3D.d.ts +409 -0
- package/templates/miniprogram/typings/types/wx/lib.wx.wasm.d.ts +152 -0
- package/templates/miniprogram/typings/types/wx/lib.wx.xr-frame.d.ts +15631 -0
- package/templates/miniprogram/variables.json +11 -0
- package/templates/service/.env +1 -0
- package/templates/service/README.md +64 -0
- package/templates/service/_gitignore +5 -0
- package/templates/service/eslint.config.js +2 -0
- package/templates/service/package.json +44 -0
- package/templates/service/prisma/schema.prisma +40 -0
- package/templates/service/prisma/sql/demoTypedSql.sql +1 -0
- package/templates/service/prisma.config.ts +12 -0
- package/templates/service/setup.js +4 -0
- package/templates/service/src/cache.ts +28 -0
- package/templates/service/src/config.ts +49 -0
- package/templates/service/src/controllers/common.ts +43 -0
- package/templates/service/src/controllers/demo-school.ts +7 -0
- package/templates/service/src/controllers/demo-student.ts +7 -0
- package/templates/service/src/controllers/index.ts +15 -0
- package/templates/service/src/database.ts +52 -0
- package/templates/service/src/index.ts +15 -0
- package/templates/service/src/logger.ts +11 -0
- package/templates/service/src/routes/demo-school.ts +9 -0
- package/templates/service/src/routes/index.ts +3 -0
- package/templates/service/src/routes/router.ts +42 -0
- package/templates/service/src/tasks/common.ts +24 -0
- package/templates/service/src/tasks/demo-school.ts +6 -0
- package/templates/service/src/tasks/index.ts +1 -0
- package/templates/service/tsconfig.build.json +9 -0
- package/templates/service/tsconfig.json +10 -0
- package/templates/site/_gitignore +3 -0
- package/templates/site/_pnpm-workspace.yaml +4 -0
- package/templates/site/eslint.config.js +19 -0
- package/templates/site/package.json +38 -0
- package/templates/site/public/favicon.png +0 -0
- package/templates/site/src/app/header.tsx +31 -0
- package/templates/site/src/app/index.tsx +38 -0
- package/templates/site/src/app/layout.tsx +63 -0
- package/templates/site/src/app/menu.tsx +115 -0
- package/templates/site/src/app/router.tsx +50 -0
- package/templates/site/src/app/style.css +9 -0
- package/templates/site/src/assets/logo.png +0 -0
- package/templates/site/src/components/Breadcrumb.tsx +47 -0
- package/templates/site/src/components/DevStatus.tsx +14 -0
- package/templates/site/src/index.html +13 -0
- package/templates/site/src/index.tsx +5 -0
- package/templates/site/src/lib/config.ts +6 -0
- package/templates/site/src/lib/logging.ts +11 -0
- package/templates/site/src/views/dashboard.tsx +7 -0
- package/templates/site/src/views/school-detail.tsx +13 -0
- package/templates/site/src/views/school-ranking.tsx +7 -0
- package/templates/site/src/views/schools.tsx +43 -0
- package/templates/site/src/views/setting.tsx +7 -0
- package/templates/site/src/views/student-score.tsx +7 -0
- package/templates/site/src/views/students.tsx +7 -0
- package/templates/site/tsconfig.json +10 -0
- package/templates/site/vite.config.js +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 安坚实
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,67 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 项目模板 - Project Templates
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
简体中文 | [English](./README_EN.md)
|
|
4
|
+
|
|
5
|
+
## 模板列表
|
|
6
|
+
|
|
7
|
+
| 目录 | 内容 | 备注 |
|
|
8
|
+
| ----------- | -------- | ------------------------------------------ |
|
|
9
|
+
| base | 基础模板 | 配置了 Prettier 和 ESLint |
|
|
10
|
+
| service | 后端服务 | TypeScript + starlight-server + Prisma ORM |
|
|
11
|
+
| site | 前端站点 | TypeScript + React + Ant Design + Vite |
|
|
12
|
+
| miniprogram | 小程序 | TypeScript + SCSS + gulp.js |
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 使用方法
|
|
17
|
+
|
|
18
|
+
```shell
|
|
19
|
+
# 这个命令本质上是执行 `npm exec @stdex/create`,即执行这个包 `package.json` 中的 `bin` 配置的脚本。
|
|
20
|
+
npm init @stdex@latest {template} -- --name=xxx
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- 若不指定 `template`,则使用 `基础模板`。
|
|
24
|
+
- 若指定 `name`,则用指定名称新建一个文件夹然后初始化项目,否则在当前目录初始化项目(要求当前目录为空)
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 开发约定
|
|
29
|
+
|
|
30
|
+
### 指定依赖版本
|
|
31
|
+
|
|
32
|
+
除非有明确的版本需要,否则 `package.json` 中的依赖版本都指定为 `latest`,项目初始化时会替换为实际版本号。
|
|
33
|
+
|
|
34
|
+
### 定义变量
|
|
35
|
+
|
|
36
|
+
在模板根目录放置 `variables.json`,格式如下:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
[
|
|
40
|
+
{
|
|
41
|
+
"name": "VARIABLE_NAME", // 变量名
|
|
42
|
+
"describe": "xxxx", // 变量介绍
|
|
43
|
+
"defaults": "xxxx" // 变量默认值,此项不存在代表是必填变量
|
|
44
|
+
},
|
|
45
|
+
...
|
|
46
|
+
]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
然后在项目任意文件中,可用 `{{VARIABLE_NAME}}` 的形式放置占位符,在初始化项目时会替换为实际变量值。
|
|
50
|
+
|
|
51
|
+
### 初始化脚本
|
|
52
|
+
|
|
53
|
+
可以在模板根目录创建一个 `setup.js`,格式如下:
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
// context 中各函数的用法见 create/src/index.js 中的同名函数
|
|
57
|
+
export async function setup(context: { command, confirmPath, getDirectoryPath }) {
|
|
58
|
+
// do something
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
此函数会在项目自动初始化流程运行完执行,之后此脚本文件会被删除。
|
|
63
|
+
|
|
64
|
+
### 指定 .gitignore
|
|
65
|
+
|
|
66
|
+
因为安装 npm 包时会自动把 `.gitignore` 重命名为 `.npmignore`,因此模板里需要把此文件命名为 `gitignore`(不带开头的点)。
|
|
67
|
+
在初始化项目时会自动重命名为 `.gitignore`。
|
package/README_EN.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Project Templates
|
|
2
|
+
|
|
3
|
+
[简体中文](./README.md) | English
|
|
4
|
+
|
|
5
|
+
## Templates
|
|
6
|
+
|
|
7
|
+
| Directory | Purpose | Notes |
|
|
8
|
+
| ----------- | --------------- | ------------------------------------------ |
|
|
9
|
+
| base | Base template | Configured with Prettier and ESLint |
|
|
10
|
+
| service | Backend service | TypeScript + starlight-server + Prisma ORM |
|
|
11
|
+
| site | Frontend site | TypeScript + React + Ant Design + Vite |
|
|
12
|
+
| miniprogram | Mini program | TypeScript + SCSS + gulp.js |
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```shell
|
|
19
|
+
# This command runs `npm exec @stdex/create`, which executes the script specified by the `bin` field in this package's `package.json`.
|
|
20
|
+
npm init @stdex@latest {template} -- --name=xxx
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- If `template` is omitted, the base template is used.
|
|
24
|
+
- If `name` is specified, a new directory with that name is created and the project is initialized inside it. Otherwise, the project is initialized in the current directory, which must be empty.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Development Conventions
|
|
29
|
+
|
|
30
|
+
### Specifying Dependency Versions
|
|
31
|
+
|
|
32
|
+
Unless a specific version is required, set dependency versions in `package.json` to `latest`. They will be replaced with the actual version numbers when the project is initialized.
|
|
33
|
+
|
|
34
|
+
### Defining Variables
|
|
35
|
+
|
|
36
|
+
Place a `variables.json` file in the template root using the following format:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
[
|
|
40
|
+
{
|
|
41
|
+
"name": "VARIABLE_NAME", // Variable name
|
|
42
|
+
"describe": "xxxx", // Variable description
|
|
43
|
+
"defaults": "xxxx" // Default value; omitting this field makes the variable required
|
|
44
|
+
},
|
|
45
|
+
...
|
|
46
|
+
]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
You can then place placeholders in the form `{{VARIABLE_NAME}}` in any project file. During project initialization, they will be replaced with the actual variable values.
|
|
50
|
+
|
|
51
|
+
### Setup Script
|
|
52
|
+
|
|
53
|
+
You can create a `setup.js` file in the template root using the following format:
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
// See the functions with the same names in create/src/index.js for details on using the functions in `context`.
|
|
57
|
+
export async function setup(context: { command, confirmPath, getDirectoryPath }) {
|
|
58
|
+
// Do something
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This function runs after the automatic project initialization process finishes. The script file is then deleted.
|
|
63
|
+
|
|
64
|
+
### Specifying .gitignore
|
|
65
|
+
|
|
66
|
+
Because installing an npm package automatically renames `.gitignore` to `.npmignore`, this file must be named `gitignore` (without the leading dot) in a template.
|
|
67
|
+
It is automatically renamed to `.gitignore` when the project is initialized.
|
package/package.json
CHANGED
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stdex/create",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "npm init 项目模板 - Project Templates For 'npm init'",
|
|
5
|
+
"homepage": "https://github.com/anjianshi/stdex-create/",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"create": "./src/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src",
|
|
12
|
+
"templates",
|
|
13
|
+
"templates/**/.env",
|
|
14
|
+
"!templates/**/node_modules",
|
|
15
|
+
"!templates/**/.swc"
|
|
16
|
+
],
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/anjianshi/stdex-create/issues",
|
|
19
|
+
"email": "anjianshi@gmail.com"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "anjianshi <anjianshi@gmail.com>",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "github:anjianshi/stdex-create"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"registry": "https://registry.npmjs.org/",
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"chalk": "^5.3.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@stdex/presets-eslint-node": "^1.0.2",
|
|
36
|
+
"@stdex/presets-prettier": "^1.0.2"
|
|
37
|
+
},
|
|
38
|
+
"prettier": "@stdex/presets-prettier/prettierrc",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"dev": "rm -rf test && node ./src/index.js base --name=test"
|
|
41
|
+
}
|
|
6
42
|
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import child_process from 'child_process'
|
|
3
|
+
import fs from 'node:fs'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import readline from 'node:readline/promises'
|
|
6
|
+
import { fileURLToPath } from 'node:url'
|
|
7
|
+
import chalk from 'chalk'
|
|
8
|
+
|
|
9
|
+
// -------------------------
|
|
10
|
+
// 工具函数
|
|
11
|
+
// -------------------------
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 返回文件所处目录的绝对路径
|
|
15
|
+
*/
|
|
16
|
+
function getDirectoryPath(fileUrl) {
|
|
17
|
+
return path.dirname(fileURLToPath(new URL(typeof fileUrl !== 'string' ? fileUrl.url : fileUrl)))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 确认路径信息
|
|
22
|
+
* @return null | 'file' | 'directory'
|
|
23
|
+
*/
|
|
24
|
+
function confirmPath(path) {
|
|
25
|
+
const stat = fs.statSync(path, { throwIfNoEntry: false })
|
|
26
|
+
if (!stat) return null
|
|
27
|
+
return stat.isDirectory() ? 'directory' : 'file'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function exit(message, code = 1) {
|
|
31
|
+
console.error(chalk.red(message))
|
|
32
|
+
process.exit(code)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 执行命令,返回 status code
|
|
37
|
+
* 若 exitOnError 为 true,执行失败时会直接退出程序
|
|
38
|
+
*/
|
|
39
|
+
async function command(command, exitOnError = true) {
|
|
40
|
+
console.log('\n> ' + chalk.green(command))
|
|
41
|
+
return new Promise(resolve => {
|
|
42
|
+
const subprocess = child_process.spawn(command, {
|
|
43
|
+
shell: true,
|
|
44
|
+
cwd: projectPath,
|
|
45
|
+
})
|
|
46
|
+
subprocess.stdout.on('data', data => process.stdout.write(chalk.gray(data)))
|
|
47
|
+
subprocess.stderr.on('data', data => process.stdout.write(chalk.red(data)))
|
|
48
|
+
subprocess.on('close', code => {
|
|
49
|
+
if (code !== 0 && exitOnError) exit('命令执行失败')
|
|
50
|
+
process.stdout.write('\n')
|
|
51
|
+
resolve(code)
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// -------------------------
|
|
57
|
+
// 整理参数
|
|
58
|
+
// -------------------------
|
|
59
|
+
|
|
60
|
+
const args = process.argv.slice(2)
|
|
61
|
+
const projectName = args
|
|
62
|
+
.map(arg => {
|
|
63
|
+
if (arg.startsWith('--name=')) return arg.slice(7)
|
|
64
|
+
return null
|
|
65
|
+
})
|
|
66
|
+
.find(v => v)
|
|
67
|
+
const projectPath = path.resolve(projectName || '.')
|
|
68
|
+
const template = args.find(arg => !arg.startsWith('--')) || 'base'
|
|
69
|
+
const templatesPath = path.resolve(getDirectoryPath(import.meta.url), '../templates')
|
|
70
|
+
const templatePath = path.resolve(templatesPath, template)
|
|
71
|
+
|
|
72
|
+
console.log('[项目初始化]')
|
|
73
|
+
if (projectName) console.log('项目名称: ' + projectName)
|
|
74
|
+
console.log('项目路径: ' + projectPath)
|
|
75
|
+
console.log('使用模板: ' + template)
|
|
76
|
+
|
|
77
|
+
// -------------------------
|
|
78
|
+
// 确认环境
|
|
79
|
+
// -------------------------
|
|
80
|
+
|
|
81
|
+
if (!templatePath.startsWith(templatesPath) || confirmPath(templatePath) !== 'directory') {
|
|
82
|
+
exit('模板不存在:' + templatePath)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const projectPathStat = confirmPath(projectPath)
|
|
86
|
+
if (projectPathStat === 'file') exit('项目路径存在同名文件,无法初始化')
|
|
87
|
+
else if (projectPathStat) {
|
|
88
|
+
if (fs.readdirSync(projectPath).length) exit('项目路径不为空,无法初始化')
|
|
89
|
+
} else {
|
|
90
|
+
fs.mkdirSync(projectPath, { recursive: true })
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// -------------------------
|
|
94
|
+
// 复制模板内容
|
|
95
|
+
// -------------------------
|
|
96
|
+
|
|
97
|
+
console.log('复制模板内容...')
|
|
98
|
+
fs.cpSync(templatePath, projectPath, {
|
|
99
|
+
recursive: true,
|
|
100
|
+
filter(src, dest) {
|
|
101
|
+
console.log(dest.slice(projectPath.length))
|
|
102
|
+
return true
|
|
103
|
+
},
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const filesToRename = [
|
|
107
|
+
{ from: '_gitignore', to: '.gitignore' },
|
|
108
|
+
{ from: '_pnpm-workspace.yaml', to: 'pnpm-workspace.yaml' },
|
|
109
|
+
]
|
|
110
|
+
for (const item of filesToRename) {
|
|
111
|
+
const fromPath = path.join(projectPath, item.from)
|
|
112
|
+
const toPath = path.join(projectPath, item.to)
|
|
113
|
+
if (confirmPath(fromPath) === 'file') {
|
|
114
|
+
fs.renameSync(fromPath, toPath)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// -------------------------
|
|
119
|
+
// 变量替换
|
|
120
|
+
// -------------------------
|
|
121
|
+
|
|
122
|
+
let variableSupportedExts =
|
|
123
|
+
'js,cjs,mjs,ts,cts,mts,jsx,tsx,json,md,html,css,scss,less,styl,txt,ini,yaml,svg'
|
|
124
|
+
variableSupportedExts = variableSupportedExts.split(',')
|
|
125
|
+
|
|
126
|
+
const variablesFile = path.join(projectPath, 'variables.json')
|
|
127
|
+
if (confirmPath(variablesFile) === 'file') {
|
|
128
|
+
const variables = JSON.parse(fs.readFileSync(variablesFile))
|
|
129
|
+
fs.unlinkSync(variablesFile)
|
|
130
|
+
if (variables.length) {
|
|
131
|
+
const values = await getVariableValues(variables)
|
|
132
|
+
await replaceVariables(values)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function getVariableValues(variables) {
|
|
137
|
+
console.log('\n[补充项目信息]')
|
|
138
|
+
const values = [] // { name, value }
|
|
139
|
+
|
|
140
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
|
|
141
|
+
for (const variable of variables) {
|
|
142
|
+
const defaults = 'defaults' in variable ? variable.defaults : undefined
|
|
143
|
+
while (true) {
|
|
144
|
+
let answer = await rl.question(
|
|
145
|
+
variable.describe + (defaults === undefined ? '' : `(${defaults})`) + ':',
|
|
146
|
+
)
|
|
147
|
+
answer = answer.trim()
|
|
148
|
+
if (!answer) {
|
|
149
|
+
if (defaults !== undefined) answer = defaults
|
|
150
|
+
else {
|
|
151
|
+
console.log(chalk.red('不能为空'))
|
|
152
|
+
continue
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
values.push({ name: variable.name, value: answer })
|
|
156
|
+
break
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
rl.close()
|
|
160
|
+
|
|
161
|
+
return values
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function replaceVariables(values) {
|
|
165
|
+
console.log('\n[替换变量]')
|
|
166
|
+
|
|
167
|
+
const directoryItems = fs.readdirSync(projectPath, { recursive: true, withFileTypes: true })
|
|
168
|
+
for (const item of directoryItems) {
|
|
169
|
+
if (!item.isFile()) continue
|
|
170
|
+
|
|
171
|
+
const filepath = path.join(item.parentPath, item.name)
|
|
172
|
+
if (!variableSupportedExts.find(ext => filepath.endsWith('.' + ext))) continue
|
|
173
|
+
|
|
174
|
+
const origContent = fs.readFileSync(filepath, 'utf8').toString()
|
|
175
|
+
let content = origContent
|
|
176
|
+
for (const { name, value } of values) {
|
|
177
|
+
const match = '{{' + name + '}}'
|
|
178
|
+
if (content.includes(match)) content = content.replaceAll(match, value)
|
|
179
|
+
}
|
|
180
|
+
if (content !== origContent) {
|
|
181
|
+
fs.writeFileSync(filepath, content)
|
|
182
|
+
console.log(filepath)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// -------------------------
|
|
188
|
+
// 安装依赖
|
|
189
|
+
// -------------------------
|
|
190
|
+
|
|
191
|
+
const packageJSONPath = path.join(projectPath, 'package.json')
|
|
192
|
+
if (confirmPath(packageJSONPath) === 'file') {
|
|
193
|
+
const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath))
|
|
194
|
+
const dependencies = Object.entries(packageJSON.dependencies || {})
|
|
195
|
+
const devDependencies = Object.entries(packageJSON.devDependencies || {})
|
|
196
|
+
if (dependencies.length || devDependencies.length) {
|
|
197
|
+
delete packageJSON.dependencies
|
|
198
|
+
delete packageJSON.devDependencies
|
|
199
|
+
fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON, null, 2))
|
|
200
|
+
|
|
201
|
+
console.log('\n[安装依赖]')
|
|
202
|
+
|
|
203
|
+
console.log('确认可用的包管理器...')
|
|
204
|
+
const usePnpm = (await command('which pnpm', true)) === 0
|
|
205
|
+
if (!usePnpm) console.log('pnpm 不存在,使用 npm 安装依赖')
|
|
206
|
+
|
|
207
|
+
const installCommand = usePnpm ? 'pnpm add ' : 'npm install '
|
|
208
|
+
if (dependencies.length) await command(installCommand + formatDependencies(dependencies))
|
|
209
|
+
if (devDependencies.length)
|
|
210
|
+
await command(installCommand + '--save-dev ' + formatDependencies(devDependencies))
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function formatDependencies(dependencies) {
|
|
215
|
+
return dependencies
|
|
216
|
+
.map(([name, ver]) => (ver !== 'latest' ? `${name}@${ver}` : name))
|
|
217
|
+
.join(' ')
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// -----------------------------
|
|
221
|
+
// 执行模板的自定义初始化脚本
|
|
222
|
+
// -----------------------------
|
|
223
|
+
|
|
224
|
+
const setupScriptPath = path.join(projectPath, 'setup.js')
|
|
225
|
+
if (confirmPath(setupScriptPath) === 'file') {
|
|
226
|
+
console.log('\n[执行初始化脚本]')
|
|
227
|
+
|
|
228
|
+
const context = { getDirectoryPath, confirmPath, command }
|
|
229
|
+
const module = await import(setupScriptPath)
|
|
230
|
+
await module.setup(context)
|
|
231
|
+
fs.unlinkSync(setupScriptPath)
|
|
232
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
console.log('hello world')
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"private": true,
|
|
3
|
+
"name": "project",
|
|
4
|
+
"description": "基础项目",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"start": "node index.js"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@stdex/presets-eslint-base": "latest",
|
|
12
|
+
"@stdex/presets-prettier": "latest",
|
|
13
|
+
"eslint": "latest"
|
|
14
|
+
},
|
|
15
|
+
"prettier": "@stdex/presets-prettier/prettierrc"
|
|
16
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# {{appname}}
|
|
2
|
+
|
|
3
|
+
## 开发
|
|
4
|
+
|
|
5
|
+
预览:运行 `pnpm watch`,然后在 `微信开发者工具` 里查看运行结果。
|
|
6
|
+
发布:运行 `pnpm build`,然后在 `微信开发者工具` 里执行发布。
|
|
7
|
+
|
|
8
|
+
## 文件结构
|
|
9
|
+
|
|
10
|
+
```yaml
|
|
11
|
+
project/
|
|
12
|
+
typings/: 小程序及自定义类型定义
|
|
13
|
+
dist/: 小程序代码构建结果,实际运行和上传的是此目录的内容
|
|
14
|
+
src/: 小程序代码
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 关于小程序类型定义
|
|
18
|
+
|
|
19
|
+
`typings/` 目录中的小程序类型定义与 TypeScript 自带的类型定义有冲突,经历过手动修改。
|
|
20
|
+
如果后续更新小程序类型定义,可能需要再次手动修改。
|
|
21
|
+
更新方法:在 `微信开发者工具` 中,右键点击 `typings/types/wx/` 目录,点击“更新声明文件”。
|
|
22
|
+
|
|
23
|
+
## 缺陷
|
|
24
|
+
|
|
25
|
+
当前不支持引入 npm 包。
|
|
26
|
+
小程序设计了引入 npm 包的机制,但是不能正确支持 ES6 Module 形式的包。
|
|
27
|
+
所以目前有需要的依赖的话,需要手动把代码复制进来。
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"pages": ["pages/index/index"],
|
|
3
|
+
"window": {},
|
|
4
|
+
"style": "v2",
|
|
5
|
+
"renderer": "skyline",
|
|
6
|
+
"rendererOptions": {
|
|
7
|
+
"skyline": {
|
|
8
|
+
"disableABTest": true,
|
|
9
|
+
"sdkVersionBegin": "3.0.0",
|
|
10
|
+
"sdkVersionEnd": "15.255.255"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"componentFramework": "glass-easel",
|
|
14
|
+
"sitemapLocation": "sitemap.json",
|
|
15
|
+
"lazyCodeLoading": "requiredComponents"
|
|
16
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: all[name]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
getAppData: function() {
|
|
13
|
+
return getAppData;
|
|
14
|
+
},
|
|
15
|
+
loadAppData: function() {
|
|
16
|
+
return loadAppData;
|
|
17
|
+
},
|
|
18
|
+
setAppData: function() {
|
|
19
|
+
return setAppData;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const initialAppData = {
|
|
23
|
+
count: 0
|
|
24
|
+
};
|
|
25
|
+
// -------------------------------
|
|
26
|
+
const dataKey = 'app-data-v1';
|
|
27
|
+
function loadAppData() {
|
|
28
|
+
return wx.getStorageSync(dataKey) || initialAppData;
|
|
29
|
+
}
|
|
30
|
+
function getAppData() {
|
|
31
|
+
return getApp().globalData;
|
|
32
|
+
}
|
|
33
|
+
function setAppData(dataOrCallback) {
|
|
34
|
+
let data;
|
|
35
|
+
if (typeof dataOrCallback === 'function') {
|
|
36
|
+
const origData = getAppData();
|
|
37
|
+
const result = dataOrCallback(origData);
|
|
38
|
+
if (typeof result === 'object') data = result;
|
|
39
|
+
else data = origData;
|
|
40
|
+
} else {
|
|
41
|
+
data = dataOrCallback;
|
|
42
|
+
}
|
|
43
|
+
getApp().globalData = data;
|
|
44
|
+
wx.setStorage({
|
|
45
|
+
key: dataKey,
|
|
46
|
+
data,
|
|
47
|
+
fail (e) {
|
|
48
|
+
console.log('保存 appData 失败', e);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _appdata = require("../../lib/app-data");
|
|
6
|
+
Page({
|
|
7
|
+
data: {
|
|
8
|
+
count: (0, _appdata.getAppData)().count
|
|
9
|
+
},
|
|
10
|
+
click () {
|
|
11
|
+
const count = this.data.count + 1;
|
|
12
|
+
this.setData({
|
|
13
|
+
count
|
|
14
|
+
});
|
|
15
|
+
(0, _appdata.setAppData)((current)=>({
|
|
16
|
+
...current,
|
|
17
|
+
count
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<view class="count" bind:tap="click">当前计数:{{count}}</view>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const globals = require('@stdex/presets-eslint-base/globals.cjs')
|
|
2
|
+
module.exports = [
|
|
3
|
+
{
|
|
4
|
+
ignores: ['dist/*'],
|
|
5
|
+
},
|
|
6
|
+
...require('@stdex/presets-eslint-typescript'),
|
|
7
|
+
{
|
|
8
|
+
languageOptions: {
|
|
9
|
+
globals: globals.browser,
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
files: ['gulpfile.js'],
|
|
14
|
+
languageOptions: {
|
|
15
|
+
globals: globals.node,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
files: ['typings/**/*.d.ts'],
|
|
20
|
+
rules: {
|
|
21
|
+
'spaced-comment': 'off',
|
|
22
|
+
'@typescript-eslint/triple-slash-reference': 'off',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
]
|