@stdex/create 0.0.0-stage → 1.2.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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +66 -2
  3. package/README_EN.md +67 -0
  4. package/package.json +40 -3
  5. package/src/eslint.config.js +2 -0
  6. package/src/index.js +233 -0
  7. package/templates/base/eslint.config.js +2 -0
  8. package/templates/base/index.js +3 -0
  9. package/templates/base/package.json +16 -0
  10. package/templates/miniprogram/README.md +27 -0
  11. package/templates/miniprogram/_gitignore +3 -0
  12. package/templates/miniprogram/eslint.config.cjs +25 -0
  13. package/templates/miniprogram/gulpfile.js +81 -0
  14. package/templates/miniprogram/package.json +22 -0
  15. package/templates/miniprogram/project.config.json +31 -0
  16. package/templates/miniprogram/project.private.config.json +8 -0
  17. package/templates/miniprogram/src/app.json +16 -0
  18. package/templates/miniprogram/src/app.scss +0 -0
  19. package/templates/miniprogram/src/app.ts +6 -0
  20. package/templates/miniprogram/src/lib/app-data.ts +46 -0
  21. package/templates/miniprogram/src/pages/index/index.json +3 -0
  22. package/templates/miniprogram/src/pages/index/index.scss +11 -0
  23. package/templates/miniprogram/src/pages/index/index.ts +13 -0
  24. package/templates/miniprogram/src/pages/index/index.wxml +1 -0
  25. package/templates/miniprogram/src/sitemap.json +9 -0
  26. package/templates/miniprogram/tsconfig.json +11 -0
  27. package/templates/miniprogram/typings/index.d.ts +5 -0
  28. package/templates/miniprogram/typings/types/index.d.ts +1 -0
  29. package/templates/miniprogram/typings/types/wx/index.d.ts +162 -0
  30. package/templates/miniprogram/typings/types/wx/lib.wx.api.d.ts +32387 -0
  31. package/templates/miniprogram/typings/types/wx/lib.wx.app.d.ts +400 -0
  32. package/templates/miniprogram/typings/types/wx/lib.wx.behavior.d.ts +68 -0
  33. package/templates/miniprogram/typings/types/wx/lib.wx.canvas.d.ts +2623 -0
  34. package/templates/miniprogram/typings/types/wx/lib.wx.cloud.d.ts +1016 -0
  35. package/templates/miniprogram/typings/types/wx/lib.wx.component.d.ts +700 -0
  36. package/templates/miniprogram/typings/types/wx/lib.wx.event.d.ts +1436 -0
  37. package/templates/miniprogram/typings/types/wx/lib.wx.page.d.ts +272 -0
  38. package/templates/miniprogram/typings/types/wx/lib.wx.phys3D.d.ts +409 -0
  39. package/templates/miniprogram/typings/types/wx/lib.wx.wasm.d.ts +152 -0
  40. package/templates/miniprogram/typings/types/wx/lib.wx.xr-frame.d.ts +15631 -0
  41. package/templates/miniprogram/variables.json +11 -0
  42. package/templates/service/README.md +64 -0
  43. package/templates/service/_env +1 -0
  44. package/templates/service/_gitignore +5 -0
  45. package/templates/service/eslint.config.js +2 -0
  46. package/templates/service/package.json +48 -0
  47. package/templates/service/prisma/schema.prisma +40 -0
  48. package/templates/service/prisma/sql/demoTypedSql.sql +1 -0
  49. package/templates/service/prisma.config.ts +12 -0
  50. package/templates/service/setup.js +4 -0
  51. package/templates/service/src/cache.ts +28 -0
  52. package/templates/service/src/config.ts +49 -0
  53. package/templates/service/src/controllers/common.ts +43 -0
  54. package/templates/service/src/controllers/demo-school.ts +7 -0
  55. package/templates/service/src/controllers/demo-student.ts +7 -0
  56. package/templates/service/src/controllers/index.ts +15 -0
  57. package/templates/service/src/database.ts +52 -0
  58. package/templates/service/src/index.ts +15 -0
  59. package/templates/service/src/logger.ts +10 -0
  60. package/templates/service/src/routes/demo-school.ts +9 -0
  61. package/templates/service/src/routes/index.ts +3 -0
  62. package/templates/service/src/routes/router.ts +42 -0
  63. package/templates/service/src/tasks/common.ts +25 -0
  64. package/templates/service/src/tasks/demo-school.ts +10 -0
  65. package/templates/service/src/tasks/index.ts +1 -0
  66. package/templates/service/tsconfig.build.json +9 -0
  67. package/templates/service/tsconfig.json +10 -0
  68. package/templates/site/_gitignore +3 -0
  69. package/templates/site/_pnpm-workspace.yaml +4 -0
  70. package/templates/site/eslint.config.js +19 -0
  71. package/templates/site/package.json +41 -0
  72. package/templates/site/public/favicon.png +0 -0
  73. package/templates/site/src/app/header.tsx +31 -0
  74. package/templates/site/src/app/index.tsx +38 -0
  75. package/templates/site/src/app/layout.tsx +63 -0
  76. package/templates/site/src/app/menu.tsx +115 -0
  77. package/templates/site/src/app/router.tsx +50 -0
  78. package/templates/site/src/app/style.css +9 -0
  79. package/templates/site/src/assets/logo.png +0 -0
  80. package/templates/site/src/components/Breadcrumb.tsx +47 -0
  81. package/templates/site/src/components/DevStatus.tsx +14 -0
  82. package/templates/site/src/index.html +13 -0
  83. package/templates/site/src/index.tsx +5 -0
  84. package/templates/site/src/lib/config.ts +6 -0
  85. package/templates/site/src/lib/init-dayjs.ts +8 -0
  86. package/templates/site/src/lib/logging.ts +5 -0
  87. package/templates/site/src/views/dashboard.tsx +7 -0
  88. package/templates/site/src/views/school-detail.tsx +13 -0
  89. package/templates/site/src/views/school-ranking.tsx +7 -0
  90. package/templates/site/src/views/schools.tsx +43 -0
  91. package/templates/site/src/views/setting.tsx +7 -0
  92. package/templates/site/src/views/student-score.tsx +7 -0
  93. package/templates/site/src/views/students.tsx +7 -0
  94. package/templates/site/tsconfig.json +10 -0
  95. 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
- # Temporary Holding Version
1
+ # 项目模板 - Project Templates
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
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,43 @@
1
1
  {
2
2
  "name": "@stdex/create",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.2.0",
4
+ "description": "npm init 项目模板 - Project Templates For 'npm init'",
5
+ "homepage": "https://github.com/anjianshi/stdex-packages/create/",
6
+ "type": "module",
7
+ "bin": {
8
+ "create": "./src/index.js"
9
+ },
10
+ "files": [
11
+ "src",
12
+ "templates",
13
+ "!templates/**/node_modules",
14
+ "!templates/**/.swc",
15
+ "!templates/**/.DS_Store",
16
+ "!templates/**/dist"
17
+ ],
18
+ "bugs": {
19
+ "url": "https://github.com/anjianshi/stdex-packages/issues",
20
+ "email": "anjianshi@gmail.com"
21
+ },
22
+ "license": "MIT",
23
+ "author": "anjianshi <anjianshi@gmail.com>",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "github:anjianshi/stdex-packages"
27
+ },
28
+ "publishConfig": {
29
+ "registry": "https://registry.npmjs.org/",
30
+ "access": "public"
31
+ },
32
+ "dependencies": {
33
+ "chalk": "^5.3.0"
34
+ },
35
+ "devDependencies": {
36
+ "@stdex/presets-eslint-node": "1.2.0",
37
+ "@stdex/presets-prettier": "1.2.0"
38
+ },
39
+ "prettier": "@stdex/presets-prettier/prettierrc",
40
+ "scripts": {
41
+ "dev": "rm -rf test && node ./src/index.js base --name=test"
42
+ }
6
43
  }
@@ -0,0 +1,2 @@
1
+ import configs from '@stdex/presets-eslint-node'
2
+ export default configs
package/src/index.js ADDED
@@ -0,0 +1,233 @@
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
+ { from: '_env', to: '.env' },
110
+ ]
111
+ for (const item of filesToRename) {
112
+ const fromPath = path.join(projectPath, item.from)
113
+ const toPath = path.join(projectPath, item.to)
114
+ if (confirmPath(fromPath) === 'file') {
115
+ fs.renameSync(fromPath, toPath)
116
+ }
117
+ }
118
+
119
+ // -------------------------
120
+ // 变量替换
121
+ // -------------------------
122
+
123
+ let variableSupportedExts =
124
+ 'js,cjs,mjs,ts,cts,mts,jsx,tsx,json,md,html,css,scss,less,styl,txt,ini,yaml,svg'
125
+ variableSupportedExts = variableSupportedExts.split(',')
126
+
127
+ const variablesFile = path.join(projectPath, 'variables.json')
128
+ if (confirmPath(variablesFile) === 'file') {
129
+ const variables = JSON.parse(fs.readFileSync(variablesFile))
130
+ fs.unlinkSync(variablesFile)
131
+ if (variables.length) {
132
+ const values = await getVariableValues(variables)
133
+ await replaceVariables(values)
134
+ }
135
+ }
136
+
137
+ async function getVariableValues(variables) {
138
+ console.log('\n[补充项目信息]')
139
+ const values = [] // { name, value }
140
+
141
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
142
+ for (const variable of variables) {
143
+ const defaults = 'defaults' in variable ? variable.defaults : undefined
144
+ while (true) {
145
+ let answer = await rl.question(
146
+ variable.describe + (defaults === undefined ? '' : `(${defaults})`) + ':',
147
+ )
148
+ answer = answer.trim()
149
+ if (!answer) {
150
+ if (defaults !== undefined) answer = defaults
151
+ else {
152
+ console.log(chalk.red('不能为空'))
153
+ continue
154
+ }
155
+ }
156
+ values.push({ name: variable.name, value: answer })
157
+ break
158
+ }
159
+ }
160
+ rl.close()
161
+
162
+ return values
163
+ }
164
+
165
+ async function replaceVariables(values) {
166
+ console.log('\n[替换变量]')
167
+
168
+ const directoryItems = fs.readdirSync(projectPath, { recursive: true, withFileTypes: true })
169
+ for (const item of directoryItems) {
170
+ if (!item.isFile()) continue
171
+
172
+ const filepath = path.join(item.parentPath, item.name)
173
+ if (!variableSupportedExts.find(ext => filepath.endsWith('.' + ext))) continue
174
+
175
+ const origContent = fs.readFileSync(filepath, 'utf8').toString()
176
+ let content = origContent
177
+ for (const { name, value } of values) {
178
+ const match = '{{' + name + '}}'
179
+ if (content.includes(match)) content = content.replaceAll(match, value)
180
+ }
181
+ if (content !== origContent) {
182
+ fs.writeFileSync(filepath, content)
183
+ console.log(filepath)
184
+ }
185
+ }
186
+ }
187
+
188
+ // -------------------------
189
+ // 安装依赖
190
+ // -------------------------
191
+
192
+ const packageJSONPath = path.join(projectPath, 'package.json')
193
+ if (confirmPath(packageJSONPath) === 'file') {
194
+ const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath))
195
+ const dependencies = Object.entries(packageJSON.dependencies || {})
196
+ const devDependencies = Object.entries(packageJSON.devDependencies || {})
197
+ if (dependencies.length || devDependencies.length) {
198
+ delete packageJSON.dependencies
199
+ delete packageJSON.devDependencies
200
+ fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON, null, 2))
201
+
202
+ console.log('\n[安装依赖]')
203
+
204
+ console.log('确认可用的包管理器...')
205
+ const usePnpm = (await command('which pnpm', true)) === 0
206
+ if (!usePnpm) console.log('pnpm 不存在,使用 npm 安装依赖')
207
+
208
+ const installCommand = usePnpm ? 'pnpm add ' : 'npm install '
209
+ if (dependencies.length) await command(installCommand + formatDependencies(dependencies))
210
+ if (devDependencies.length)
211
+ await command(installCommand + '--save-dev ' + formatDependencies(devDependencies))
212
+ }
213
+ }
214
+
215
+ function formatDependencies(dependencies) {
216
+ return dependencies
217
+ .map(([name, ver]) => (ver !== 'latest' ? `${name}@${ver}` : name))
218
+ .join(' ')
219
+ }
220
+
221
+ // -----------------------------
222
+ // 执行模板的自定义初始化脚本
223
+ // -----------------------------
224
+
225
+ const setupScriptPath = path.join(projectPath, 'setup.js')
226
+ if (confirmPath(setupScriptPath) === 'file') {
227
+ console.log('\n[执行初始化脚本]')
228
+
229
+ const context = { getDirectoryPath, confirmPath, command }
230
+ const module = await import(setupScriptPath)
231
+ await module.setup(context)
232
+ fs.unlinkSync(setupScriptPath)
233
+ }
@@ -0,0 +1,2 @@
1
+ import configs from '@stdex/presets-eslint-base'
2
+ export default configs
@@ -0,0 +1,3 @@
1
+ export function run() {
2
+ return 1
3
+ }
@@ -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": "workspace:*",
12
+ "@stdex/presets-prettier": "workspace:*",
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,3 @@
1
+ .DS_Store
2
+ node_modules/
3
+ dist/
@@ -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
+ ]
@@ -0,0 +1,81 @@
1
+ const childProcess = require('node:child_process')
2
+ const gulp = require('gulp')
3
+ const renamePlugin = require('gulp-rename')
4
+ const sassPluginFactory = require('gulp-sass')
5
+ const swcPlugin = require('gulp-swc')
6
+ const dartSass = require('sass')
7
+ const { replaceTscAliasPaths } = require('tsc-alias')
8
+
9
+ const sassPlugin = sassPluginFactory(dartSass)
10
+
11
+ /**
12
+ * --------------------
13
+ * 常量定义
14
+ * --------------------
15
+ */
16
+ const dist = 'dist/'
17
+
18
+ /**
19
+ * --------------------
20
+ * 任务定义
21
+ * --------------------
22
+ */
23
+ function clean(cb) {
24
+ childProcess.exec(`rm -rf ${dist}`, (err, stdout, stderr) => {
25
+ if (stdout.trim()) process.stdout.write(stdout)
26
+ if (stderr.trim()) process.stderr.write(stderr)
27
+ cb()
28
+ })
29
+ }
30
+
31
+ function typescript(cb, path) {
32
+ const swcOptions = {
33
+ jsc: {
34
+ target: 'ES2019', // 编译到较新的语法,但不是最新的(不然 ?. 语言小程序不支持)
35
+ },
36
+ module: {
37
+ type: 'commonjs', // 编译成 commonjs 模块,因为小程序原生不支持 ES6 Module
38
+ },
39
+ }
40
+ return gulp
41
+ .src(path || 'src/**/*.ts', { base: './src' })
42
+ .pipe(swcPlugin(swcOptions))
43
+ .pipe(gulp.dest(dist))
44
+ }
45
+
46
+ function tsAlias(cb) {
47
+ replaceTscAliasPaths().then(cb)
48
+ }
49
+
50
+ function sass(cb, path) {
51
+ return gulp
52
+ .src(path || 'src/**/*.scss', { base: './src' })
53
+ .pipe(sassPlugin().on('error', sassPlugin.logError))
54
+ .pipe(renamePlugin({ extname: '.wxss' }))
55
+ .pipe(gulp.dest(dist))
56
+ }
57
+
58
+ function assets(cb, path) {
59
+ return gulp
60
+ .src(path || ['src/**/*.*', '!src/**/*.(ts|scss)'], { base: './src', encoding: false })
61
+ .pipe(gulp.dest(dist))
62
+ }
63
+
64
+ function watch() {
65
+ function handler(path) {
66
+ if (path.endsWith('.ts')) return gulp.series(typescript.bind(null, null, path), tsAlias)()
67
+ else if (path.endsWith('.scss')) return sass(null, path)
68
+ else return assets(null, path)
69
+ }
70
+ gulp.watch('src/**/*').on('add', handler).on('change', handler)
71
+ }
72
+
73
+ /**
74
+ * --------------------
75
+ * 导出任务
76
+ * --------------------
77
+ */
78
+ const build = gulp.series(clean, gulp.parallel(gulp.series(typescript, tsAlias), sass, assets))
79
+ exports.build = build
80
+
81
+ exports.watch = gulp.series(build, watch)
@@ -0,0 +1,22 @@
1
+ {
2
+ "private": true,
3
+ "name": "project",
4
+ "version": "1.0.0",
5
+ "scripts": {
6
+ "watch": "gulp watch",
7
+ "build": "gulp build"
8
+ },
9
+ "devDependencies": {
10
+ "@stdex/presets-eslint-typescript": "workspace:*",
11
+ "@stdex/presets-prettier": "workspace:*",
12
+ "@stdex/presets-typescript": "workspace:*",
13
+ "@swc/core": "latest",
14
+ "gulp": "latest",
15
+ "gulp-rename": "latest",
16
+ "gulp-sass": "latest",
17
+ "gulp-swc": "latest",
18
+ "sass": "latest",
19
+ "tsc-alias": "latest"
20
+ },
21
+ "prettier": "@stdex/presets-prettier/prettierrc"
22
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "appid": "{{appid}}",
3
+ "compileType": "miniprogram",
4
+ "condition": {},
5
+ "description": "项目配置文件",
6
+ "editorSetting": {
7
+ "tabIndent": "insertSpaces",
8
+ "tabSize": 2
9
+ },
10
+ "libVersion": "widelyUsed",
11
+ "miniprogramRoot": "dist/",
12
+ "packOptions": {
13
+ "ignore": [],
14
+ "include": []
15
+ },
16
+ "setting": {
17
+ "babelSetting": {
18
+ "ignore": [],
19
+ "disablePlugins": [],
20
+ "outputPath": ""
21
+ },
22
+ "coverView": true,
23
+ "minified": true,
24
+ "postcss": true,
25
+ "showShadowRootInWxmlPanel": true,
26
+ "skylineRenderEnable": true
27
+ },
28
+ "simulatorType": "wechat",
29
+ "simulatorPluginLibVersion": {},
30
+ "srcMiniprogramRoot": "dist/"
31
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
3
+ "projectname": "{{appname}}",
4
+ "setting": {
5
+ "compileHotReLoad": true
6
+ },
7
+ "condition": {}
8
+ }