@xunlei-open/create-miniapp 0.1.1-beta.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 (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -0
  3. package/dist/index.mjs +416 -0
  4. package/dist/index.mjs.map +1 -0
  5. package/package.json +59 -0
  6. package/templates/react/.prettierignore +3 -0
  7. package/templates/react/.prettierrc.ejs +7 -0
  8. package/templates/react/_gitignore +24 -0
  9. package/templates/react/biome.json +41 -0
  10. package/templates/react/eslint.config.js.ejs +43 -0
  11. package/templates/react/index.html.ejs +12 -0
  12. package/templates/react/jsconfig.json +9 -0
  13. package/templates/react/manifest.json +16 -0
  14. package/templates/react/miniapp.config.js.ejs +16 -0
  15. package/templates/react/package.json.ejs +42 -0
  16. package/templates/react/src/App.jsx.ejs +53 -0
  17. package/templates/react/src/index.css +105 -0
  18. package/templates/react/src/main.jsx +10 -0
  19. package/templates/react/tests/App.spec.jsx.ejs +12 -0
  20. package/templates/react/vitest.config.js +11 -0
  21. package/templates/react-ts/.prettierignore +3 -0
  22. package/templates/react-ts/.prettierrc.ejs +7 -0
  23. package/templates/react-ts/_gitignore +25 -0
  24. package/templates/react-ts/biome.json +41 -0
  25. package/templates/react-ts/eslint.config.js.ejs +33 -0
  26. package/templates/react-ts/index.html.ejs +12 -0
  27. package/templates/react-ts/manifest.json +16 -0
  28. package/templates/react-ts/miniapp.config.ts.ejs +16 -0
  29. package/templates/react-ts/package.json.ejs +48 -0
  30. package/templates/react-ts/src/App.tsx.ejs +53 -0
  31. package/templates/react-ts/src/index.css +105 -0
  32. package/templates/react-ts/src/main.tsx +10 -0
  33. package/templates/react-ts/src/vite-env.d.ts +2 -0
  34. package/templates/react-ts/tests/App.spec.tsx.ejs +12 -0
  35. package/templates/react-ts/tsconfig.app.json +28 -0
  36. package/templates/react-ts/tsconfig.json +7 -0
  37. package/templates/react-ts/tsconfig.node.json +24 -0
  38. package/templates/react-ts/vitest.config.js +11 -0
  39. package/templates/vanilla/.prettierignore +3 -0
  40. package/templates/vanilla/.prettierrc.ejs +7 -0
  41. package/templates/vanilla/_gitignore +23 -0
  42. package/templates/vanilla/biome.json +40 -0
  43. package/templates/vanilla/eslint.config.js.ejs +25 -0
  44. package/templates/vanilla/index.html.ejs +12 -0
  45. package/templates/vanilla/jsconfig.json +8 -0
  46. package/templates/vanilla/manifest.json +16 -0
  47. package/templates/vanilla/miniapp.config.js.ejs +15 -0
  48. package/templates/vanilla/package.json.ejs +33 -0
  49. package/templates/vanilla/src/main.js.ejs +54 -0
  50. package/templates/vanilla/src/style.css +101 -0
  51. package/templates/vanilla/tests/example.spec.js +7 -0
  52. package/templates/vanilla-ts/.prettierignore +3 -0
  53. package/templates/vanilla-ts/.prettierrc.ejs +7 -0
  54. package/templates/vanilla-ts/_gitignore +23 -0
  55. package/templates/vanilla-ts/biome.json +40 -0
  56. package/templates/vanilla-ts/eslint.config.js.ejs +36 -0
  57. package/templates/vanilla-ts/index.html.ejs +12 -0
  58. package/templates/vanilla-ts/manifest.json +16 -0
  59. package/templates/vanilla-ts/miniapp.config.ts.ejs +15 -0
  60. package/templates/vanilla-ts/package.json.ejs +38 -0
  61. package/templates/vanilla-ts/src/main.ts.ejs +54 -0
  62. package/templates/vanilla-ts/src/style.css +101 -0
  63. package/templates/vanilla-ts/src/vite-env.d.ts +2 -0
  64. package/templates/vanilla-ts/tests/example.spec.ts +7 -0
  65. package/templates/vanilla-ts/tsconfig.json +26 -0
  66. package/templates/vue/.prettierignore +3 -0
  67. package/templates/vue/.prettierrc.ejs +7 -0
  68. package/templates/vue/_gitignore +25 -0
  69. package/templates/vue/biome.json +46 -0
  70. package/templates/vue/eslint.config.js.ejs +26 -0
  71. package/templates/vue/index.html.ejs +12 -0
  72. package/templates/vue/jsconfig.json +8 -0
  73. package/templates/vue/manifest.json +16 -0
  74. package/templates/vue/miniapp.config.js.ejs +16 -0
  75. package/templates/vue/package.json.ejs +39 -0
  76. package/templates/vue/src/App.vue.ejs +51 -0
  77. package/templates/vue/src/assets/main.css +105 -0
  78. package/templates/vue/src/main.js +5 -0
  79. package/templates/vue/tests/App.spec.js.ejs +12 -0
  80. package/templates/vue/vitest.config.js +11 -0
  81. package/templates/vue-ts/.prettierignore +3 -0
  82. package/templates/vue-ts/.prettierrc.ejs +7 -0
  83. package/templates/vue-ts/_gitignore +25 -0
  84. package/templates/vue-ts/biome.json +46 -0
  85. package/templates/vue-ts/eslint.config.js.ejs +32 -0
  86. package/templates/vue-ts/index.html.ejs +12 -0
  87. package/templates/vue-ts/manifest.json +16 -0
  88. package/templates/vue-ts/miniapp.config.ts.ejs +16 -0
  89. package/templates/vue-ts/package.json.ejs +46 -0
  90. package/templates/vue-ts/src/App.vue.ejs +51 -0
  91. package/templates/vue-ts/src/assets/main.css +105 -0
  92. package/templates/vue-ts/src/main.ts +5 -0
  93. package/templates/vue-ts/src/vite-env.d.ts +2 -0
  94. package/templates/vue-ts/tests/App.spec.ts.ejs +12 -0
  95. package/templates/vue-ts/tsconfig.app.json +17 -0
  96. package/templates/vue-ts/tsconfig.json +7 -0
  97. package/templates/vue-ts/tsconfig.node.json +24 -0
  98. package/templates/vue-ts/vitest.config.js +11 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "semi": false,
3
+ "singleQuote": true,
4
+ "trailingComma": "all",
5
+ "printWidth": 120,
6
+ "endOfLine": "auto"
7
+ }
@@ -0,0 +1,24 @@
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
+ node_modules
11
+ dist
12
+ dist-ssr
13
+ release
14
+ *.local
15
+ coverage
16
+
17
+ # Editor directories and files
18
+ .idea
19
+ .DS_Store
20
+ *.suo
21
+ *.ntvs*
22
+ *.njsproj
23
+ *.sln
24
+ *.sw?
@@ -0,0 +1,41 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.4.16/schema.json",
3
+ "vcs": {
4
+ "enabled": false
5
+ },
6
+ "files": {
7
+ "ignoreUnknown": false
8
+ },
9
+ "formatter": {
10
+ "enabled": true,
11
+ "indentStyle": "tab",
12
+ "indentWidth": 2,
13
+ "lineWidth": 120,
14
+ "lineEnding": "auto"
15
+ },
16
+ "linter": {
17
+ "enabled": true,
18
+ "rules": {
19
+ "recommended": true,
20
+ "correctness": {
21
+ "noUndeclaredVariables": "error"
22
+ }
23
+ }
24
+ },
25
+ "javascript": {
26
+ "jsxRuntime": "transparent",
27
+ "formatter": {
28
+ "semicolons": "asNeeded",
29
+ "quoteStyle": "single",
30
+ "trailingCommas": "all"
31
+ }
32
+ },
33
+ "assist": {
34
+ "enabled": true,
35
+ "actions": {
36
+ "source": {
37
+ "organizeImports": "on"
38
+ }
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,43 @@
1
+ import js from '@eslint/js'
2
+ import react from 'eslint-plugin-react'
3
+ import reactHooks from 'eslint-plugin-react-hooks'
4
+ import reactRefresh from 'eslint-plugin-react-refresh'
5
+ import globals from 'globals'
6
+ import eslintConfigPrettier from 'eslint-config-prettier'
7
+ import eslintPluginPrettier from 'eslint-plugin-prettier'
8
+
9
+ export default [
10
+ { ignores: ['dist', 'node_modules'] },
11
+ js.configs.recommended,
12
+ react.configs.flat.recommended,
13
+ react.configs.flat['jsx-runtime'],
14
+ eslintConfigPrettier,
15
+ {
16
+ files: ['**/*.{js,jsx}'],
17
+ settings: {
18
+ react: { version: 'detect' },
19
+ },
20
+ plugins: {
21
+ prettier: eslintPluginPrettier,
22
+ 'react-hooks': reactHooks,
23
+ 'react-refresh': reactRefresh,
24
+ },
25
+ rules: {
26
+ 'prettier/prettier': 'error',
27
+ ...reactHooks.configs.recommended.rules,
28
+ 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
29
+ },
30
+ languageOptions: {
31
+ ecmaVersion: 'latest',
32
+ sourceType: 'module',
33
+ globals: {
34
+ ...globals.browser,
35
+ xunlei: 'readonly',
36
+ MessageError: 'readonly',
37
+ },
38
+ parserOptions: {
39
+ ecmaFeatures: { jsx: true },
40
+ },
41
+ },
42
+ },
43
+ ]
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title><%= projectName %></title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.jsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,9 @@
1
+ {
2
+ "compilerOptions": {
3
+ "jsx": "react-jsx",
4
+ "paths": {
5
+ "@/*": ["./src/*"]
6
+ }
7
+ },
8
+ "exclude": ["node_modules", "dist"]
9
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "manifest_version": 1,
3
+ "name": "示例插件",
4
+ "title": "示例插件",
5
+ "description": "一个迅雷微应用示例",
6
+ "version": "1.0.0",
7
+ "entry": {
8
+ "type": "miniapp",
9
+ "url": "index.html"
10
+ },
11
+ "window": {
12
+ "width": 900,
13
+ "height": 700
14
+ },
15
+ "permissions": ["tasks.create"]
16
+ }
@@ -0,0 +1,16 @@
1
+ import { fileURLToPath, URL } from 'node:url'
2
+ import { defineConfig } from '@xunlei-open/miniapp'
3
+
4
+ export default defineConfig({
5
+ modules: ['@xunlei-open/miniapp-module-react'],
6
+ vite: {
7
+ resolve: {
8
+ alias: {
9
+ '@': fileURLToPath(new URL('./src', import.meta.url)),
10
+ },
11
+ },
12
+ build: {
13
+ target: 'es2015',
14
+ },
15
+ },
16
+ })
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "<%= packageName %>",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "engines": {
6
+ "node": ">=20.19.0"
7
+ },
8
+ "type": "module",
9
+ "scripts": {
10
+ "dev": "xunlei-miniapp",
11
+ "build": "xunlei-miniapp build",
12
+ "package": "xunlei-miniapp package"<% if (features.includes('vitest')) { %>,
13
+ "test": "vitest run",
14
+ "test:watch": "vitest"<% } %><% if (features.includes('lint')) { %>,
15
+ "lint": "eslint .",
16
+ "format": "prettier --write ."<% } %><% if (features.includes('biome')) { %>,
17
+ "lint": "biome check .",
18
+ "format": "biome format --write ."<% } %>
19
+ },
20
+ "dependencies": {
21
+ "react": "^19.0.0",
22
+ "react-dom": "^19.0.0"
23
+ },
24
+ "devDependencies": {
25
+ "@xunlei-open/miniapp-module-react": "^<%= devkitVersion %>",
26
+ "@xunlei-open/miniapp": "^<%= devkitVersion %>",
27
+ "vite": "^8.0.12"<% if (features.includes('vitest')) { %>,
28
+ "@testing-library/react": "^16.2.0",
29
+ "jsdom": "^29.0.0",
30
+ "vitest": "^4.1.0"<% } %><% if (features.includes('lint')) { %>,
31
+ "@eslint/js": "^9.22.0",
32
+ "eslint": "^9.22.0",
33
+ "eslint-config-prettier": "^10.1.1",
34
+ "eslint-plugin-prettier": "^5.4.0",
35
+ "eslint-plugin-react": "^7.37.5",
36
+ "eslint-plugin-react-hooks": "^5.2.0",
37
+ "eslint-plugin-react-refresh": "^0.4.19",
38
+ "globals": "^16.0.0",
39
+ "prettier": "^3.5.3"<% } %><% if (features.includes('biome')) { %>,
40
+ "@biomejs/biome": "2.4.16"<% } %>
41
+ }
42
+ }
@@ -0,0 +1,53 @@
1
+ import { useState } from 'react'
2
+
3
+ export default function App() {
4
+ const [url, setUrl] = useState('https://example.com/file.zip')
5
+ const [result, setResult] = useState('等待创建任务')
6
+ const [submitting, setSubmitting] = useState(false)
7
+
8
+ async function createTask(event) {
9
+ event.preventDefault()
10
+
11
+ if (typeof xunlei === 'undefined') {
12
+ setResult('当前是普通浏览器预览,请在迅雷微应用宿主中创建任务。')
13
+ return
14
+ }
15
+
16
+ setSubmitting(true)
17
+ setResult('正在创建任务…')
18
+
19
+ try {
20
+ const task = await xunlei.tasks.create({
21
+ req: { url },
22
+ opts: { name: '<%= projectName %>' },
23
+ })
24
+ setResult(`任务已创建:${task.id}`)
25
+ } catch (error) {
26
+ setResult(error instanceof Error ? error.message : String(error))
27
+ } finally {
28
+ setSubmitting(false)
29
+ }
30
+ }
31
+
32
+ return (
33
+ <div className="app">
34
+ <main>
35
+ <p className="eyebrow">Xunlei Miniapp</p>
36
+ <h1><%= projectName %></h1>
37
+ <p className="intro">输入下载地址,通过迅雷微应用 API 创建下载任务。</p>
38
+
39
+ <form onSubmit={createTask}>
40
+ <label htmlFor="task-url">下载地址</label>
41
+ <div className="row">
42
+ <input id="task-url" type="url" value={url} onChange={(event) => setUrl(event.target.value)} required />
43
+ <button type="submit" disabled={submitting}>
44
+ {submitting ? '正在创建…' : '创建任务'}
45
+ </button>
46
+ </div>
47
+ </form>
48
+
49
+ <output>{result}</output>
50
+ </main>
51
+ </div>
52
+ )
53
+ }
@@ -0,0 +1,105 @@
1
+ :root {
2
+ font-family: Inter, ui-sans-serif, system-ui, sans-serif;
3
+ color: #172033;
4
+ background: #eef3ff;
5
+ font-synthesis: none;
6
+ }
7
+
8
+ * {
9
+ box-sizing: border-box;
10
+ }
11
+
12
+ body {
13
+ min-width: 320px;
14
+ min-height: 100vh;
15
+ margin: 0;
16
+ }
17
+
18
+ .app {
19
+ min-height: 100vh;
20
+ display: grid;
21
+ place-items: center;
22
+ }
23
+
24
+ main {
25
+ width: min(680px, calc(100vw - 48px));
26
+ padding: 40px;
27
+ border: 1px solid #d5def2;
28
+ border-radius: 20px;
29
+ background: #fff;
30
+ box-shadow: 0 20px 60px rgb(36 65 120 / 12%);
31
+ }
32
+
33
+ .eyebrow {
34
+ margin: 0;
35
+ color: #176bff;
36
+ font-size: 12px;
37
+ font-weight: 700;
38
+ letter-spacing: 0.12em;
39
+ text-transform: uppercase;
40
+ }
41
+
42
+ h1 {
43
+ margin: 8px 0;
44
+ }
45
+
46
+ .intro {
47
+ margin: 0 0 28px;
48
+ color: #596780;
49
+ }
50
+
51
+ label {
52
+ display: block;
53
+ margin-bottom: 8px;
54
+ font-size: 14px;
55
+ font-weight: 600;
56
+ }
57
+
58
+ .row {
59
+ display: flex;
60
+ gap: 10px;
61
+ }
62
+
63
+ input,
64
+ button {
65
+ min-height: 44px;
66
+ border-radius: 10px;
67
+ font: inherit;
68
+ }
69
+
70
+ input {
71
+ flex: 1;
72
+ min-width: 0;
73
+ padding: 0 12px;
74
+ border: 1px solid #b9c6df;
75
+ }
76
+
77
+ button {
78
+ padding: 0 18px;
79
+ border: 0;
80
+ color: #fff;
81
+ background: #176bff;
82
+ cursor: pointer;
83
+ }
84
+
85
+ button:disabled {
86
+ cursor: wait;
87
+ opacity: 0.65;
88
+ }
89
+
90
+ output {
91
+ display: block;
92
+ margin-top: 18px;
93
+ color: #596780;
94
+ font-size: 14px;
95
+ }
96
+
97
+ @media (max-width: 560px) {
98
+ main {
99
+ padding: 28px;
100
+ }
101
+
102
+ .row {
103
+ flex-direction: column;
104
+ }
105
+ }
@@ -0,0 +1,10 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import App from './App.jsx'
4
+ import './index.css'
5
+
6
+ createRoot(document.getElementById('root')).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ )
@@ -0,0 +1,12 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { render } from '@testing-library/react'
4
+ import { describe, expect, it } from 'vitest'
5
+ import App from '../src/App.jsx'
6
+
7
+ describe('App', () => {
8
+ it('renders project title', () => {
9
+ const { container } = render(<App />)
10
+ expect(container.textContent).toContain('<%= projectName %>')
11
+ })
12
+ })
@@ -0,0 +1,11 @@
1
+ import { fileURLToPath } from 'node:url'
2
+ import { defineConfig } from 'vitest/config'
3
+ import { loadMiniappConfig } from '@xunlei-open/miniapp'
4
+
5
+ export default defineConfig(async () => {
6
+ const config = await loadMiniappConfig(fileURLToPath(new URL('.', import.meta.url)), {
7
+ command: 'serve',
8
+ mode: 'test',
9
+ })
10
+ return config.vite
11
+ })
@@ -0,0 +1,3 @@
1
+ dist
2
+ node_modules
3
+ pnpm-lock.yaml
@@ -0,0 +1,7 @@
1
+ {
2
+ "semi": false,
3
+ "singleQuote": true,
4
+ "trailingComma": "all",
5
+ "printWidth": 120,
6
+ "endOfLine": "auto"
7
+ }
@@ -0,0 +1,25 @@
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
+ node_modules
11
+ dist
12
+ dist-ssr
13
+ release
14
+ *.local
15
+ coverage
16
+ *.tsbuildinfo
17
+
18
+ # Editor directories and files
19
+ .idea
20
+ .DS_Store
21
+ *.suo
22
+ *.ntvs*
23
+ *.njsproj
24
+ *.sln
25
+ *.sw?
@@ -0,0 +1,41 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.4.16/schema.json",
3
+ "vcs": {
4
+ "enabled": false
5
+ },
6
+ "files": {
7
+ "ignoreUnknown": false
8
+ },
9
+ "formatter": {
10
+ "enabled": true,
11
+ "indentStyle": "tab",
12
+ "indentWidth": 2,
13
+ "lineWidth": 120,
14
+ "lineEnding": "auto"
15
+ },
16
+ "linter": {
17
+ "enabled": true,
18
+ "rules": {
19
+ "recommended": true,
20
+ "correctness": {
21
+ "noUndeclaredVariables": "error"
22
+ }
23
+ }
24
+ },
25
+ "javascript": {
26
+ "jsxRuntime": "transparent",
27
+ "formatter": {
28
+ "semicolons": "asNeeded",
29
+ "quoteStyle": "single",
30
+ "trailingCommas": "all"
31
+ }
32
+ },
33
+ "assist": {
34
+ "enabled": true,
35
+ "actions": {
36
+ "source": {
37
+ "organizeImports": "on"
38
+ }
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,33 @@
1
+ import js from '@eslint/js'
2
+ import reactHooks from 'eslint-plugin-react-hooks'
3
+ import reactRefresh from 'eslint-plugin-react-refresh'
4
+ import globals from 'globals'
5
+ import tseslint from 'typescript-eslint'
6
+ import eslintConfigPrettier from 'eslint-config-prettier'
7
+ import eslintPluginPrettier from 'eslint-plugin-prettier'
8
+
9
+ export default tseslint.config(
10
+ { ignores: ['dist', 'node_modules'] },
11
+ js.configs.recommended,
12
+ ...tseslint.configs.recommended,
13
+ eslintConfigPrettier,
14
+ {
15
+ files: ['**/*.{ts,tsx}'],
16
+ plugins: {
17
+ prettier: eslintPluginPrettier,
18
+ 'react-hooks': reactHooks,
19
+ 'react-refresh': reactRefresh,
20
+ },
21
+ rules: {
22
+ 'prettier/prettier': 'error',
23
+ '@typescript-eslint/no-unused-vars': 'off',
24
+ 'no-fallthrough': 'off',
25
+ ...reactHooks.configs.recommended.rules,
26
+ 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
27
+ },
28
+ languageOptions: {
29
+ ecmaVersion: 'latest',
30
+ globals: globals.browser,
31
+ },
32
+ },
33
+ )
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title><%= projectName %></title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,16 @@
1
+ {
2
+ "manifest_version": 1,
3
+ "name": "示例插件",
4
+ "title": "示例插件",
5
+ "description": "一个迅雷微应用示例",
6
+ "version": "1.0.0",
7
+ "entry": {
8
+ "type": "miniapp",
9
+ "url": "index.html"
10
+ },
11
+ "window": {
12
+ "width": 900,
13
+ "height": 700
14
+ },
15
+ "permissions": ["tasks.create"]
16
+ }
@@ -0,0 +1,16 @@
1
+ import { fileURLToPath, URL } from 'node:url'
2
+ import { defineConfig } from '@xunlei-open/miniapp'
3
+
4
+ export default defineConfig({
5
+ modules: ['@xunlei-open/miniapp-module-react'],
6
+ vite: {
7
+ resolve: {
8
+ alias: {
9
+ '@': fileURLToPath(new URL('./src', import.meta.url)),
10
+ },
11
+ },
12
+ build: {
13
+ target: 'es2015',
14
+ },
15
+ },
16
+ })
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "<%= packageName %>",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "engines": {
6
+ "node": ">=20.19.0"
7
+ },
8
+ "type": "module",
9
+ "scripts": {
10
+ "dev": "xunlei-miniapp",
11
+ "build": "xunlei-miniapp build",
12
+ "package": "xunlei-miniapp package",
13
+ "typecheck": "tsc -b"<% if (features.includes('vitest')) { %>,
14
+ "test": "vitest run",
15
+ "test:watch": "vitest"<% } %><% if (features.includes('lint')) { %>,
16
+ "lint": "eslint .",
17
+ "format": "prettier --write ."<% } %><% if (features.includes('biome')) { %>,
18
+ "lint": "biome check .",
19
+ "format": "biome format --write ."<% } %>
20
+ },
21
+ "dependencies": {
22
+ "react": "^19.0.0",
23
+ "react-dom": "^19.0.0"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^22.13.10",
27
+ "@types/react": "^19.0.10",
28
+ "@types/react-dom": "^19.0.4",
29
+ "@xunlei-open/miniapp-module-react": "^<%= devkitVersion %>",
30
+ "typescript": "~6.0.2",
31
+ "@xunlei-open/miniapp-types": "^<%= devkitVersion %>",
32
+ "@xunlei-open/miniapp": "^<%= devkitVersion %>",
33
+ "vite": "^8.0.12"<% if (features.includes('vitest')) { %>,
34
+ "@testing-library/react": "^16.2.0",
35
+ "jsdom": "^29.0.0",
36
+ "vitest": "^4.1.0"<% } %><% if (features.includes('lint')) { %>,
37
+ "@eslint/js": "^9.22.0",
38
+ "eslint": "^9.22.0",
39
+ "eslint-config-prettier": "^10.1.1",
40
+ "eslint-plugin-prettier": "^5.4.0",
41
+ "eslint-plugin-react-hooks": "^5.2.0",
42
+ "eslint-plugin-react-refresh": "^0.4.19",
43
+ "globals": "^16.0.0",
44
+ "prettier": "^3.5.3",
45
+ "typescript-eslint": "^8.26.1"<% } %><% if (features.includes('biome')) { %>,
46
+ "@biomejs/biome": "2.4.16"<% } %>
47
+ }
48
+ }
@@ -0,0 +1,53 @@
1
+ import { useState, type FormEvent } from 'react'
2
+
3
+ export default function App() {
4
+ const [url, setUrl] = useState('https://example.com/file.zip')
5
+ const [result, setResult] = useState('等待创建任务')
6
+ const [submitting, setSubmitting] = useState(false)
7
+
8
+ async function createTask(event: FormEvent<HTMLFormElement>) {
9
+ event.preventDefault()
10
+
11
+ if (typeof xunlei === 'undefined') {
12
+ setResult('当前是普通浏览器预览,请在迅雷微应用宿主中创建任务。')
13
+ return
14
+ }
15
+
16
+ setSubmitting(true)
17
+ setResult('正在创建任务…')
18
+
19
+ try {
20
+ const task = await xunlei.tasks.create({
21
+ req: { url },
22
+ opts: { name: '<%= projectName %>' },
23
+ })
24
+ setResult(`任务已创建:${task.id}`)
25
+ } catch (error) {
26
+ setResult(error instanceof Error ? error.message : String(error))
27
+ } finally {
28
+ setSubmitting(false)
29
+ }
30
+ }
31
+
32
+ return (
33
+ <div className="app">
34
+ <main>
35
+ <p className="eyebrow">Xunlei Miniapp</p>
36
+ <h1><%= projectName %></h1>
37
+ <p className="intro">输入下载地址,通过迅雷微应用 API 创建下载任务。</p>
38
+
39
+ <form onSubmit={createTask}>
40
+ <label htmlFor="task-url">下载地址</label>
41
+ <div className="row">
42
+ <input id="task-url" type="url" value={url} onChange={(event) => setUrl(event.target.value)} required />
43
+ <button type="submit" disabled={submitting}>
44
+ {submitting ? '正在创建…' : '创建任务'}
45
+ </button>
46
+ </div>
47
+ </form>
48
+
49
+ <output>{result}</output>
50
+ </main>
51
+ </div>
52
+ )
53
+ }