@taro-minify-pack/helper 0.1.4-alpha.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/.eslintrc.js +20 -0
- package/LICENSE +21 -0
- package/README.md +246 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/uploader/adapter/define-adapter.d.ts +2 -0
- package/dist/uploader/adapter/define-adapter.js +6 -0
- package/dist/uploader/adapter/define-adapter.js.map +1 -0
- package/dist/uploader/adapter/index.d.ts +2 -0
- package/dist/uploader/adapter/index.js +19 -0
- package/dist/uploader/adapter/index.js.map +1 -0
- package/dist/uploader/adapter/upload-adapter-ali-oss.d.ts +8 -0
- package/dist/uploader/adapter/upload-adapter-ali-oss.js +67 -0
- package/dist/uploader/adapter/upload-adapter-ali-oss.js.map +1 -0
- package/dist/uploader/index.d.ts +10 -0
- package/dist/uploader/index.js +52 -0
- package/dist/uploader/index.js.map +1 -0
- package/dist/uploader/types.d.ts +14 -0
- package/dist/uploader/types.js +3 -0
- package/dist/uploader/types.js.map +1 -0
- package/dist/uploader/utils.d.ts +8 -0
- package/dist/uploader/utils.js +32 -0
- package/dist/uploader/utils.js.map +1 -0
- package/package.json +38 -0
- package/src/index.ts +1 -0
- package/src/uploader/adapter/define-adapter.ts +3 -0
- package/src/uploader/adapter/index.ts +2 -0
- package/src/uploader/adapter/upload-adapter-ali-oss.ts +51 -0
- package/src/uploader/index.ts +35 -0
- package/src/uploader/types.ts +17 -0
- package/src/uploader/utils.ts +24 -0
- package/tsconfig.json +21 -0
package/.eslintrc.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
env: {
|
|
3
|
+
node: true,
|
|
4
|
+
es6: true
|
|
5
|
+
},
|
|
6
|
+
extends: [
|
|
7
|
+
'standard',
|
|
8
|
+
'plugin:@typescript-eslint/recommended'
|
|
9
|
+
],
|
|
10
|
+
parser: '@typescript-eslint/parser',
|
|
11
|
+
plugins: ['@typescript-eslint'],
|
|
12
|
+
rules: {
|
|
13
|
+
'@typescript-eslint/no-empty-function': 'off',
|
|
14
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
15
|
+
'@typescript-eslint/no-var-requires': 'off',
|
|
16
|
+
'@typescript-eslint/no-non-null-assertion': 'off',
|
|
17
|
+
'@typescript-eslint/ban-ts-comment': 'off',
|
|
18
|
+
'no-use-before-define': 'off'
|
|
19
|
+
}
|
|
20
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 yu.pan
|
|
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
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
## @taro-minify-pack/preset
|
|
2
|
+
|
|
3
|
+
> 预设配置,整合了 @taro-minify-pack 系列核心插件,提供一键式优化解决方案,简化 Taro 项目的性能优化配置。
|
|
4
|
+
|
|
5
|
+
该预设包含以下插件:
|
|
6
|
+
|
|
7
|
+
- `@taro-minify-pack/plugin-async-pack`: 异步加载主包代码,优化主包体积
|
|
8
|
+
- `@taro-minify-pack/plugin-remote-assets`: 远程资源上传,优化主包体积
|
|
9
|
+
- `@taro-minify-pack/plugin-cover-browserslist`: 根据微信小程序基础库版本自动设置 browserslist
|
|
10
|
+
- `@taro-minify-pack/plugin-bundle-analyzer`: 包体积分析工具
|
|
11
|
+
|
|
12
|
+
## ✨ 功能特性
|
|
13
|
+
|
|
14
|
+
| 插件名称 | 功能描述 |
|
|
15
|
+
|---------------------------------------------|-----------------------------------------------|
|
|
16
|
+
| @taro-minify-pack/plugin-async-pack | 实现主包代码的异步加载,显著减小主包体积,提升小程序启动性能 |
|
|
17
|
+
| @taro-minify-pack/plugin-remote-assets | 将静态资源上传到远程 CDN,减少主包大小,加快资源加载速度 |
|
|
18
|
+
| @taro-minify-pack/plugin-cover-browserslist | 根据微信小程序基础库版本自动设置 browserslist,减少不必要的 polyfill |
|
|
19
|
+
| @taro-minify-pack/plugin-bundle-analyzer | 可视化分析包体积,帮助识别体积过大的模块和依赖 |
|
|
20
|
+
|
|
21
|
+
## 📦 安装
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# 使用 npm
|
|
25
|
+
npm install @taro-minify-pack/preset
|
|
26
|
+
|
|
27
|
+
# 使用 yarn
|
|
28
|
+
yarn add @taro-minify-pack/preset
|
|
29
|
+
|
|
30
|
+
# 使用 pnpm
|
|
31
|
+
pnpm add @taro-minify-pack/preset
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 🛠️ 配置
|
|
35
|
+
|
|
36
|
+
### Babel 配置
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// babel-preset-taro 更多选项和默认值:
|
|
40
|
+
// https://docs.taro.zone/docs/next/babel-config
|
|
41
|
+
module.exports = {
|
|
42
|
+
presets: [
|
|
43
|
+
['taro', {
|
|
44
|
+
framework: 'react',
|
|
45
|
+
ts: true,
|
|
46
|
+
compiler: 'webpack5',
|
|
47
|
+
// 在原有基础上添加这个配置即可
|
|
48
|
+
'dynamic-import-node': process.env.TARO_ENV !== 'weapp',
|
|
49
|
+
}]
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Taro 配置
|
|
55
|
+
|
|
56
|
+
#### 基础配置示例
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
// config/index.js
|
|
60
|
+
const path = require('path')
|
|
61
|
+
const {aliOssUploadAdapter} = require('@taro-minify-pack/preset')
|
|
62
|
+
|
|
63
|
+
module.exports = {
|
|
64
|
+
compiler: {
|
|
65
|
+
type: 'webpack5',
|
|
66
|
+
prebundle: {
|
|
67
|
+
// 关闭预打包,与分包异步编译有冲突
|
|
68
|
+
enable: false,
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
presets: [
|
|
72
|
+
['@taro-minify-pack/preset', {
|
|
73
|
+
// 开启远程资源上传,优化主包体积
|
|
74
|
+
remoteAssets: {
|
|
75
|
+
pathAlias: {
|
|
76
|
+
'@': path.resolve(__dirname, '../src/'),
|
|
77
|
+
'~@': path.resolve(__dirname, '../src/'),
|
|
78
|
+
},
|
|
79
|
+
assetsDirPath: path.resolve(__dirname, '../src/assets/'),
|
|
80
|
+
uploader: aliOssUploadAdapter({
|
|
81
|
+
customDomain: 'https://your-custom-domain.com',
|
|
82
|
+
accessKeyId: 'your-access-key-id',
|
|
83
|
+
accessKeySecret: 'your-access-key-secret',
|
|
84
|
+
bucket: 'your-bucket-name',
|
|
85
|
+
bucketDir: 'bucketDir',
|
|
86
|
+
region: 'your-region',
|
|
87
|
+
})
|
|
88
|
+
},
|
|
89
|
+
// 自动设置 browserslist 配置
|
|
90
|
+
coverBrowsersList: {
|
|
91
|
+
// 必填:微信小程序基础库最低版本号
|
|
92
|
+
minBaseLibraryVersion: '2.14.4'
|
|
93
|
+
},
|
|
94
|
+
// 包体积分析配置
|
|
95
|
+
bundleAnalyzer: true,
|
|
96
|
+
// 开启异步加载主包代码,优化主包体积
|
|
97
|
+
asyncPack: true
|
|
98
|
+
}],
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### 完整配置示例
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
// config/index.js
|
|
107
|
+
const path = require('path')
|
|
108
|
+
const {aliOssUploadAdapter} = require('@taro-minify-pack/remote-assets-adapter-ali-oss')
|
|
109
|
+
|
|
110
|
+
module.exports = {
|
|
111
|
+
compiler: {
|
|
112
|
+
type: 'webpack5',
|
|
113
|
+
prebundle: {
|
|
114
|
+
// 关闭预打包,与分包异步编译有冲突
|
|
115
|
+
enable: false,
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
presets: [
|
|
119
|
+
['@taro-minify-pack/preset', {
|
|
120
|
+
// 远程资源上传配置
|
|
121
|
+
remoteAssets: {
|
|
122
|
+
pathAlias: {
|
|
123
|
+
'@': path.resolve(__dirname, '../src/'),
|
|
124
|
+
'~@': path.resolve(__dirname, '../src/'),
|
|
125
|
+
},
|
|
126
|
+
assetsDirPath: path.resolve(__dirname, '../src/assets/'),
|
|
127
|
+
uploader: aliOssUploadAdapter({
|
|
128
|
+
customDomain: 'https://your-custom-domain.com',
|
|
129
|
+
accessKeyId: 'your-access-key-id',
|
|
130
|
+
accessKeySecret: 'your-access-key-secret',
|
|
131
|
+
bucket: 'your-bucket-name',
|
|
132
|
+
bucketDir: 'bucketDir',
|
|
133
|
+
region: 'your-region',
|
|
134
|
+
})
|
|
135
|
+
},
|
|
136
|
+
// 异步加载主包代码配置
|
|
137
|
+
asyncPack: {
|
|
138
|
+
// 动态包名称前缀
|
|
139
|
+
dynamicPackageNamePrefix: 'dynamic-package',
|
|
140
|
+
// 动态包数量
|
|
141
|
+
dynamicPackageCount: 1,
|
|
142
|
+
// 自定义异步分包
|
|
143
|
+
customDynamicPackages: [
|
|
144
|
+
{
|
|
145
|
+
name: 'sync-style',
|
|
146
|
+
test: (module) => /src[\\/]pages[\\/]sync-style[\\/]/.test(module.identifier()),
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: 'async-style',
|
|
150
|
+
test: (module) => /src[\\/]pages[\\/]async-style[\\/]/.test(module.identifier()),
|
|
151
|
+
asyncStyle: true
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
},
|
|
155
|
+
// 自动设置 browserslist 配置
|
|
156
|
+
coverBrowsersList: {
|
|
157
|
+
// 必填:微信小程序基础库最低版本号
|
|
158
|
+
minBaseLibraryVersion: '2.14.4'
|
|
159
|
+
},
|
|
160
|
+
// 包体积分析配置
|
|
161
|
+
bundleAnalyzer: {
|
|
162
|
+
// 服务器主机
|
|
163
|
+
analyzerHost: '127.0.0.1',
|
|
164
|
+
// 服务器端口
|
|
165
|
+
analyzerPort: 8888,
|
|
166
|
+
// 是否自动打开报告
|
|
167
|
+
openAnalyzer: true
|
|
168
|
+
}
|
|
169
|
+
}],
|
|
170
|
+
],
|
|
171
|
+
};
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## 📋 配置选项
|
|
175
|
+
|
|
176
|
+
### 通用配置
|
|
177
|
+
|
|
178
|
+
| 选项名 | 类型 | 默认值 | 描述 |
|
|
179
|
+
|-------------------|----------------------------------|---------|-----------------------------|
|
|
180
|
+
| asyncPack | `boolean` \| `AsyncPackOpts` | `false` | 异步加载主包代码配置,设为 `true` 使用默认配置 |
|
|
181
|
+
| remoteAssets | `RemoteAssetPluginOpt` | - | 远程资源上传配置 |
|
|
182
|
+
| coverBrowsersList | `CoverBrowsersListOpt` | - | 自动设置 browserslist 配置 |
|
|
183
|
+
| bundleAnalyzer | `boolean` \| `BundleAnalyzerOpt` | `false` | 包体积分析配置,设为 `true` 使用默认配置 |
|
|
184
|
+
|
|
185
|
+
### asyncPack 配置
|
|
186
|
+
|
|
187
|
+
| 选项名 | 类型 | 默认值 | 描述 |
|
|
188
|
+
|--------------------------|--------------------------|---------------------|-----------|
|
|
189
|
+
| dynamicPackageNamePrefix | `string` | `'dynamic-package'` | 动态包名称前缀 |
|
|
190
|
+
| dynamicPackageCount | `number` | `1` | 动态包数量 |
|
|
191
|
+
| customDynamicPackages | `CustomDynamicPackage[]` | `[]` | 自定义异步分包配置 |
|
|
192
|
+
|
|
193
|
+
### remoteAssets 配置
|
|
194
|
+
|
|
195
|
+
| 选项名 | 类型 | 默认值 | 描述 |
|
|
196
|
+
|---------------|--------------------------|-----|--------------|
|
|
197
|
+
| assetsDirPath | `string` | - | 静态资源目录路径(必填) |
|
|
198
|
+
| pathAlias | `Record<string, string>` | - | 路径别名配置 |
|
|
199
|
+
| uploader | `Function` | - | 资源上传适配器函数 |
|
|
200
|
+
|
|
201
|
+
### coverBrowsersList 配置
|
|
202
|
+
|
|
203
|
+
| 选项名 | 类型 | 默认值 | 描述 |
|
|
204
|
+
|-----------------------|----------|-----|-------------------|
|
|
205
|
+
| minBaseLibraryVersion | `string` | - | 微信小程序基础库最低版本号(必填) |
|
|
206
|
+
|
|
207
|
+
### bundleAnalyzer 配置
|
|
208
|
+
|
|
209
|
+
| 选项名 | 类型 | 默认值 | 描述 |
|
|
210
|
+
|--------------|----------------------|---------------|----------|
|
|
211
|
+
| analyzerHost | `string` | `'127.0.0.1'` | 服务器主机 |
|
|
212
|
+
| analyzerPort | `number` \| `'auto'` | `8888` | 服务器端口 |
|
|
213
|
+
| openAnalyzer | `boolean` | `true` | 是否自动打开报告 |
|
|
214
|
+
|
|
215
|
+
## 🎯 使用场景
|
|
216
|
+
|
|
217
|
+
* 需要快速优化 Taro 项目性能的场景
|
|
218
|
+
* 希望简化多插件配置的项目
|
|
219
|
+
* 需要同时使用多个 @taro-minify-pack 系列插件的项目
|
|
220
|
+
* 对小程序主包体积有严格要求的项目
|
|
221
|
+
|
|
222
|
+
## ⚠️ 注意事项
|
|
223
|
+
|
|
224
|
+
1. **预打包冲突**:当启用 `asyncPack` 时,必须关闭 Taro 的预打包功能(`compiler.prebundle.enable = false`),否则会导致构建冲突。
|
|
225
|
+
|
|
226
|
+
2. **Babel 配置**:必须在 Babel 配置中添加 `'dynamic-import-node': process.env.TARO_ENV !== 'weapp'`,以确保异步加载功能在不同环境下正常工作。
|
|
227
|
+
|
|
228
|
+
3. **远程资源上传**:使用 `remoteAssets` 时,需要提供有效的上传适配器和配置信息,确保资源能够正确上传到远程服务器。
|
|
229
|
+
|
|
230
|
+
4. **基础库版本**:使用 `coverBrowsersList` 时,必须指定正确的微信小程序基础库版本,以确保生成的代码兼容目标环境。
|
|
231
|
+
|
|
232
|
+
5. **Webpack 版本**:该预设仅支持 Webpack 5 编译器,请确保 Taro 项目使用 `compiler.type = 'webpack5'`。
|
|
233
|
+
|
|
234
|
+
6. **remote-assets 插件版本兼容性**:
|
|
235
|
+
- **Taro < 4.0.10**:由于 `@tarojs/webpack5-runner` 不支持使用绝对路径注册 PostCSS 插件,在低版本 Taro 中直接使用本插件可能会导致插件无法生效。如需在低版本中使用,请参考官方 Pull Request( `https://github.com/NervJS/taro/pull/18683/files` ) 自行 patch。
|
|
236
|
+
- **Taro ≥ 4.0.10**:可直接使用,无需额外处理。
|
|
237
|
+
|
|
238
|
+
## 📄 许可证
|
|
239
|
+
|
|
240
|
+
MIT License
|
|
241
|
+
|
|
242
|
+
## 🤝 贡献
|
|
243
|
+
|
|
244
|
+
欢迎提交 Issues 和 Pull Requests!
|
|
245
|
+
|
|
246
|
+
> 该预设是 @taro-minify-pack 系列插件的一部分,致力于提供完整的 Taro 项目优化解决方案。
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './uploader';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./uploader"), exports);
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA0B"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defineUploaderAdapter = void 0;
|
|
4
|
+
const defineUploaderAdapter = (adapter) => adapter;
|
|
5
|
+
exports.defineUploaderAdapter = defineUploaderAdapter;
|
|
6
|
+
//# sourceMappingURL=define-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-adapter.js","sourceRoot":"","sources":["../../../src/uploader/adapter/define-adapter.ts"],"names":[],"mappings":";;;AAEO,MAAM,qBAAqB,GAAG,CAAI,OAA2B,EAAE,EAAE,CAAC,OAAO,CAAA;AAAnE,QAAA,qBAAqB,yBAA8C"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./upload-adapter-ali-oss"), exports);
|
|
18
|
+
__exportStar(require("./define-adapter"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/uploader/adapter/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2DAAwC;AACxC,mDAAgC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { LocalAssetInfo } from '../types';
|
|
2
|
+
import AliOss from 'ali-oss';
|
|
3
|
+
export interface AliOssUploadAdapterOpt extends AliOss.Options {
|
|
4
|
+
fileName?: (localAssetInfo: LocalAssetInfo) => string;
|
|
5
|
+
customDomain?: string;
|
|
6
|
+
bucketDir?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const aliOssUploadAdapter: import("../types").UploaderAdapter<AliOssUploadAdapterOpt>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
12
|
+
var t = {};
|
|
13
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
14
|
+
t[p] = s[p];
|
|
15
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
16
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
17
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
18
|
+
t[p[i]] = s[p[i]];
|
|
19
|
+
}
|
|
20
|
+
return t;
|
|
21
|
+
};
|
|
22
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
23
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.aliOssUploadAdapter = void 0;
|
|
27
|
+
const define_adapter_1 = require("./define-adapter");
|
|
28
|
+
const ali_oss_1 = __importDefault(require("ali-oss"));
|
|
29
|
+
const defaultFileName = (localAssetInfo) => localAssetInfo.uniqueKey;
|
|
30
|
+
exports.aliOssUploadAdapter = (0, define_adapter_1.defineUploaderAdapter)((opt) => {
|
|
31
|
+
const { customDomain, bucketDir = '', fileName = defaultFileName } = opt, aliOssOpt = __rest(opt, ["customDomain", "bucketDir", "fileName"]);
|
|
32
|
+
const client = new ali_oss_1.default(aliOssOpt);
|
|
33
|
+
const isRemoteAssetExist = (...args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
34
|
+
try {
|
|
35
|
+
yield client.head(...args);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (error.code === 'NoSuchKey')
|
|
40
|
+
return false;
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const uploadToAliOss = (...args) => __awaiter(void 0, void 0, void 0, function* () { return client.put(...args); });
|
|
45
|
+
const getRemoteAssetPath = (localAssetInfo) => {
|
|
46
|
+
const { ext } = localAssetInfo;
|
|
47
|
+
return `${bucketDir}/${fileName(localAssetInfo)}${ext}`;
|
|
48
|
+
};
|
|
49
|
+
const getRemoteAssetUrl = (localAssetInfo) => {
|
|
50
|
+
const { ext } = localAssetInfo;
|
|
51
|
+
if (customDomain)
|
|
52
|
+
return `${customDomain}/${fileName(localAssetInfo)}${ext}`;
|
|
53
|
+
const remotePath = getRemoteAssetPath(localAssetInfo);
|
|
54
|
+
return client.signatureUrl(remotePath);
|
|
55
|
+
};
|
|
56
|
+
return (localAssetInfo) => __awaiter(void 0, void 0, void 0, function* () {
|
|
57
|
+
const { localPath } = localAssetInfo;
|
|
58
|
+
const remoteAssetPath = getRemoteAssetPath(localAssetInfo);
|
|
59
|
+
const remoteAssetUrl = getRemoteAssetUrl(localAssetInfo);
|
|
60
|
+
const isExist = yield isRemoteAssetExist(remoteAssetPath);
|
|
61
|
+
if (isExist)
|
|
62
|
+
return Object.assign(Object.assign({}, localAssetInfo), { remoteUrl: remoteAssetUrl });
|
|
63
|
+
yield uploadToAliOss(remoteAssetPath, localPath);
|
|
64
|
+
return Object.assign(Object.assign({}, localAssetInfo), { remoteUrl: remoteAssetUrl });
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=upload-adapter-ali-oss.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-adapter-ali-oss.js","sourceRoot":"","sources":["../../../src/uploader/adapter/upload-adapter-ali-oss.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qDAAwD;AAExD,sDAA4B;AAE5B,MAAM,eAAe,GAAG,CAAC,cAA8B,EAAE,EAAE,CAAC,cAAc,CAAC,SAAS,CAAA;AAQvE,QAAA,mBAAmB,GAAG,IAAA,sCAAqB,EAAC,CAAC,GAA2B,EAAE,EAAE;IACvF,MAAM,EAAE,YAAY,EAAE,SAAS,GAAG,EAAE,EAAE,QAAQ,GAAG,eAAe,KAAmB,GAAG,EAAjB,SAAS,UAAK,GAAG,EAAhF,yCAA0E,CAAM,CAAA;IAEtF,MAAM,MAAM,GAAG,IAAI,iBAAM,CAAC,SAAS,CAAC,CAAA;IAEpC,MAAM,kBAAkB,GAAG,CAAO,GAAG,IAAgC,EAAE,EAAE;QACvE,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAA;YAC1B,OAAO,IAAI,CAAA;QACb,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;gBAAE,OAAO,KAAK,CAAA;YAC5C,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC,CAAA,CAAA;IAED,MAAM,cAAc,GAAG,CAAO,GAAG,IAA+B,EAAE,EAAE,kDAAC,OAAA,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAA,GAAA,CAAA;IAExF,MAAM,kBAAkB,GAAG,CAAC,cAA8B,EAAE,EAAE;QAC5D,MAAM,EAAE,GAAG,EAAE,GAAG,cAAc,CAAA;QAC9B,OAAO,GAAG,SAAS,IAAI,QAAQ,CAAC,cAAc,CAAC,GAAG,GAAG,EAAE,CAAA;IACzD,CAAC,CAAA;IAED,MAAM,iBAAiB,GAAG,CAAC,cAA8B,EAAE,EAAE;QAC3D,MAAM,EAAE,GAAG,EAAE,GAAG,cAAc,CAAA;QAC9B,IAAI,YAAY;YAAE,OAAO,GAAG,YAAY,IAAI,QAAQ,CAAC,cAAc,CAAC,GAAG,GAAG,EAAE,CAAA;QAC5E,MAAM,UAAU,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAA;QACrD,OAAO,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAA;IACxC,CAAC,CAAA;IAED,OAAO,CAAO,cAA8B,EAAE,EAAE;QAC9C,MAAM,EAAE,SAAS,EAAE,GAAG,cAAc,CAAA;QACpC,MAAM,eAAe,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAA;QAC1D,MAAM,cAAc,GAAG,iBAAiB,CAAC,cAAc,CAAC,CAAA;QACxD,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,eAAe,CAAC,CAAA;QACzD,IAAI,OAAO;YAAE,uCAAY,cAAc,KAAE,SAAS,EAAE,cAAc,IAAE;QACpE,MAAM,cAAc,CAAC,eAAe,EAAE,SAAS,CAAC,CAAA;QAChD,uCAAY,cAAc,KAAE,SAAS,EAAE,cAAc,IAAE;IACzD,CAAC,CAAA,CAAA;AACH,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { LocalAssetInfo, Uploader } from './types';
|
|
2
|
+
interface UploaderOpt {
|
|
3
|
+
upload?: Uploader;
|
|
4
|
+
payload?: any;
|
|
5
|
+
assetsDirPath?: string;
|
|
6
|
+
processAssets?: (assets: LocalAssetInfo[]) => LocalAssetInfo[];
|
|
7
|
+
}
|
|
8
|
+
export * from './adapter';
|
|
9
|
+
export * from './types';
|
|
10
|
+
export declare const uploadAssets: (opt: UploaderOpt) => Promise<import("./types").RemoteAssetInfo[]>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
17
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
18
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
19
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
20
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
21
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
22
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.uploadAssets = void 0;
|
|
30
|
+
const promise_pool_1 = require("@supercharge/promise-pool");
|
|
31
|
+
const utils_1 = require("./utils");
|
|
32
|
+
const path_1 = __importDefault(require("path"));
|
|
33
|
+
__exportStar(require("./adapter"), exports);
|
|
34
|
+
__exportStar(require("./types"), exports);
|
|
35
|
+
const uploadAssets = (opt) => __awaiter(void 0, void 0, void 0, function* () {
|
|
36
|
+
const { assetsDirPath, upload, payload, processAssets = (assets) => assets } = opt;
|
|
37
|
+
if (!assetsDirPath || !upload)
|
|
38
|
+
return [];
|
|
39
|
+
const assetsPaths = (0, utils_1.travelFiles)(assetsDirPath);
|
|
40
|
+
const assetsInfos = assetsPaths.reduce((result, localPath) => {
|
|
41
|
+
const uniqueKey = (0, utils_1.generateFileUniqueKey)(localPath);
|
|
42
|
+
const { ext } = path_1.default.parse(localPath);
|
|
43
|
+
const fileName = path_1.default.parse(localPath).name;
|
|
44
|
+
return [...result, { localPath, ext, uniqueKey, fileName }];
|
|
45
|
+
}, []);
|
|
46
|
+
const { results: remoteAssetInfoList } = yield promise_pool_1.PromisePool.withConcurrency(2)
|
|
47
|
+
.for(processAssets(assetsInfos))
|
|
48
|
+
.process((localAssetInfo) => __awaiter(void 0, void 0, void 0, function* () { return upload(localAssetInfo, payload); }));
|
|
49
|
+
return remoteAssetInfoList.filter(Boolean);
|
|
50
|
+
});
|
|
51
|
+
exports.uploadAssets = uploadAssets;
|
|
52
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/uploader/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4DAAuD;AAEvD,mCAA4D;AAC5D,gDAAuB;AASvB,4CAAyB;AACzB,0CAAuB;AAEhB,MAAM,YAAY,GAAG,CAAO,GAAgB,EAAE,EAAE;IACrD,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,GAAG,CAAA;IAElF,IAAI,CAAC,aAAa,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAA;IAExC,MAAM,WAAW,GAAG,IAAA,mBAAW,EAAC,aAAa,CAAC,CAAA;IAE9C,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE;QAC7E,MAAM,SAAS,GAAG,IAAA,6BAAqB,EAAC,SAAS,CAAC,CAAA;QAClD,MAAM,EAAE,GAAG,EAAE,GAAG,cAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;QACrC,MAAM,QAAQ,GAAG,cAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAA;QAC3C,OAAO,CAAC,GAAG,MAAM,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAA;IAC7D,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE,GAAG,MAAM,0BAAW,CAAC,eAAe,CAAC,CAAC,CAAC;SAC1E,GAAG,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;SAC/B,OAAO,CAAC,CAAO,cAAc,EAAE,EAAE,kDAAC,OAAA,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAA,GAAA,CAAC,CAAA;IAErE,OAAO,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;AAC5C,CAAC,CAAA,CAAA;AAnBY,QAAA,YAAY,gBAmBxB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface LocalAssetInfo {
|
|
2
|
+
localPath: string;
|
|
3
|
+
fileName: string;
|
|
4
|
+
uniqueKey: string;
|
|
5
|
+
ext: string;
|
|
6
|
+
}
|
|
7
|
+
export interface RemoteAssetInfo {
|
|
8
|
+
ext: string;
|
|
9
|
+
localPath: string;
|
|
10
|
+
uniqueKey: string;
|
|
11
|
+
remoteUrl: string;
|
|
12
|
+
}
|
|
13
|
+
export type Uploader = (localAssetInfo: LocalAssetInfo, payload?: any) => Promise<RemoteAssetInfo>;
|
|
14
|
+
export type UploaderAdapter<T = any> = (opt: T) => Uploader;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/uploader/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateFileUniqueKey = exports.travelFiles = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const md5_1 = __importDefault(require("md5"));
|
|
10
|
+
/**
|
|
11
|
+
* 递归查找文件
|
|
12
|
+
*/
|
|
13
|
+
const travelFiles = (dir) => {
|
|
14
|
+
const files = fs_1.default.readdirSync(dir);
|
|
15
|
+
return files.reduce((result, file) => {
|
|
16
|
+
const filePath = path_1.default.join(dir, file);
|
|
17
|
+
if (!fs_1.default.statSync(filePath).isDirectory())
|
|
18
|
+
return [...result, filePath];
|
|
19
|
+
return [...result, ...(0, exports.travelFiles)(filePath)];
|
|
20
|
+
}, []);
|
|
21
|
+
};
|
|
22
|
+
exports.travelFiles = travelFiles;
|
|
23
|
+
/**
|
|
24
|
+
* 生成文件 key
|
|
25
|
+
*/
|
|
26
|
+
const generateFileUniqueKey = (filePath) => {
|
|
27
|
+
const { dir, base } = path_1.default.parse(filePath);
|
|
28
|
+
const buffer = fs_1.default.readFileSync(`${dir}${path_1.default.sep}${base}`);
|
|
29
|
+
return (0, md5_1.default)(buffer);
|
|
30
|
+
};
|
|
31
|
+
exports.generateFileUniqueKey = generateFileUniqueKey;
|
|
32
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/uploader/utils.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAmB;AACnB,gDAAuB;AACvB,8CAAqB;AAErB;;GAEG;AACI,MAAM,WAAW,GAAG,CAAC,GAAW,EAAY,EAAE;IACnD,MAAM,KAAK,GAAG,YAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IACjC,OAAO,KAAK,CAAC,MAAM,CAAW,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;QAC7C,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QACrC,IAAI,CAAC,YAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE;YAAE,OAAO,CAAC,GAAG,MAAM,EAAE,QAAQ,CAAC,CAAA;QACtE,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,IAAA,mBAAW,EAAC,QAAQ,CAAC,CAAC,CAAA;IAC9C,CAAC,EAAE,EAAE,CAAC,CAAA;AACR,CAAC,CAAA;AAPY,QAAA,WAAW,eAOvB;AAED;;GAEG;AACI,MAAM,qBAAqB,GAAG,CAAC,QAAgB,EAAE,EAAE;IACxD,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,cAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,YAAE,CAAC,YAAY,CAAC,GAAG,GAAG,GAAG,cAAI,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC,CAAA;IAC1D,OAAO,IAAA,aAAG,EAAC,MAAM,CAAC,CAAA;AACpB,CAAC,CAAA;AAJY,QAAA,qBAAqB,yBAIjC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@taro-minify-pack/helper",
|
|
3
|
+
"version": "0.1.4-alpha.3",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"homepage": "https://github.com/panyu97py/taro-minify-pack",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/panyu97py/taro-minify-pack.git"
|
|
14
|
+
},
|
|
15
|
+
"author": "yu.pan",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@supercharge/promise-pool": "^3.2.0",
|
|
19
|
+
"ali-oss": "^6.23.0",
|
|
20
|
+
"md5": "^2.3.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/ali-oss": "^6.16.13",
|
|
24
|
+
"@types/md5": "^2.3.5",
|
|
25
|
+
"@types/node": "^18.19.130",
|
|
26
|
+
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
|
27
|
+
"@typescript-eslint/parser": "^8.26.1",
|
|
28
|
+
"eslint": "^8.19.0",
|
|
29
|
+
"eslint-config-standard": "^17.0.0",
|
|
30
|
+
"eslint-plugin-import": "^2.26.0",
|
|
31
|
+
"eslint-plugin-n": "^15.2.3",
|
|
32
|
+
"eslint-plugin-promise": "^6.0.0",
|
|
33
|
+
"typescript": "^5.8.2"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc"
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './uploader'
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { defineUploaderAdapter } from './define-adapter'
|
|
2
|
+
import { LocalAssetInfo } from '../types'
|
|
3
|
+
import AliOss from 'ali-oss'
|
|
4
|
+
|
|
5
|
+
const defaultFileName = (localAssetInfo: LocalAssetInfo) => localAssetInfo.uniqueKey
|
|
6
|
+
|
|
7
|
+
export interface AliOssUploadAdapterOpt extends AliOss.Options {
|
|
8
|
+
fileName?: (localAssetInfo: LocalAssetInfo)=>string
|
|
9
|
+
customDomain?: string
|
|
10
|
+
bucketDir?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const aliOssUploadAdapter = defineUploaderAdapter((opt: AliOssUploadAdapterOpt) => {
|
|
14
|
+
const { customDomain, bucketDir = '', fileName = defaultFileName, ...aliOssOpt } = opt
|
|
15
|
+
|
|
16
|
+
const client = new AliOss(aliOssOpt)
|
|
17
|
+
|
|
18
|
+
const isRemoteAssetExist = async (...args: Parameters<AliOss['head']>) => {
|
|
19
|
+
try {
|
|
20
|
+
await client.head(...args)
|
|
21
|
+
return true
|
|
22
|
+
} catch (error: any) {
|
|
23
|
+
if (error.code === 'NoSuchKey') return false
|
|
24
|
+
throw error
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const uploadToAliOss = async (...args: Parameters<AliOss['put']>) => client.put(...args)
|
|
29
|
+
|
|
30
|
+
const getRemoteAssetPath = (localAssetInfo: LocalAssetInfo) => {
|
|
31
|
+
const { ext } = localAssetInfo
|
|
32
|
+
return `${bucketDir}/${fileName(localAssetInfo)}${ext}`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const getRemoteAssetUrl = (localAssetInfo: LocalAssetInfo) => {
|
|
36
|
+
const { ext } = localAssetInfo
|
|
37
|
+
if (customDomain) return `${customDomain}/${fileName(localAssetInfo)}${ext}`
|
|
38
|
+
const remotePath = getRemoteAssetPath(localAssetInfo)
|
|
39
|
+
return client.signatureUrl(remotePath)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return async (localAssetInfo: LocalAssetInfo) => {
|
|
43
|
+
const { localPath } = localAssetInfo
|
|
44
|
+
const remoteAssetPath = getRemoteAssetPath(localAssetInfo)
|
|
45
|
+
const remoteAssetUrl = getRemoteAssetUrl(localAssetInfo)
|
|
46
|
+
const isExist = await isRemoteAssetExist(remoteAssetPath)
|
|
47
|
+
if (isExist) return { ...localAssetInfo, remoteUrl: remoteAssetUrl }
|
|
48
|
+
await uploadToAliOss(remoteAssetPath, localPath)
|
|
49
|
+
return { ...localAssetInfo, remoteUrl: remoteAssetUrl }
|
|
50
|
+
}
|
|
51
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { PromisePool } from '@supercharge/promise-pool'
|
|
2
|
+
import { LocalAssetInfo, Uploader } from './types'
|
|
3
|
+
import { generateFileUniqueKey, travelFiles } from './utils'
|
|
4
|
+
import path from 'path'
|
|
5
|
+
|
|
6
|
+
interface UploaderOpt {
|
|
7
|
+
upload?: Uploader
|
|
8
|
+
payload?: any
|
|
9
|
+
assetsDirPath?: string,
|
|
10
|
+
processAssets?: (assets: LocalAssetInfo[]) => LocalAssetInfo[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export * from './adapter'
|
|
14
|
+
export * from './types'
|
|
15
|
+
|
|
16
|
+
export const uploadAssets = async (opt: UploaderOpt) => {
|
|
17
|
+
const { assetsDirPath, upload, payload, processAssets = (assets) => assets } = opt
|
|
18
|
+
|
|
19
|
+
if (!assetsDirPath || !upload) return []
|
|
20
|
+
|
|
21
|
+
const assetsPaths = travelFiles(assetsDirPath)
|
|
22
|
+
|
|
23
|
+
const assetsInfos = assetsPaths.reduce<LocalAssetInfo[]>((result, localPath) => {
|
|
24
|
+
const uniqueKey = generateFileUniqueKey(localPath)
|
|
25
|
+
const { ext } = path.parse(localPath)
|
|
26
|
+
const fileName = path.parse(localPath).name
|
|
27
|
+
return [...result, { localPath, ext, uniqueKey, fileName }]
|
|
28
|
+
}, [])
|
|
29
|
+
|
|
30
|
+
const { results: remoteAssetInfoList } = await PromisePool.withConcurrency(2)
|
|
31
|
+
.for(processAssets(assetsInfos))
|
|
32
|
+
.process(async (localAssetInfo) => upload(localAssetInfo, payload))
|
|
33
|
+
|
|
34
|
+
return remoteAssetInfoList.filter(Boolean)
|
|
35
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface LocalAssetInfo {
|
|
2
|
+
localPath: string,
|
|
3
|
+
fileName: string,
|
|
4
|
+
uniqueKey: string,
|
|
5
|
+
ext: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface RemoteAssetInfo {
|
|
9
|
+
ext: string,
|
|
10
|
+
localPath: string,
|
|
11
|
+
uniqueKey: string,
|
|
12
|
+
remoteUrl: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type Uploader = (localAssetInfo: LocalAssetInfo, payload?: any) => Promise<RemoteAssetInfo>
|
|
16
|
+
|
|
17
|
+
export type UploaderAdapter<T = any> = (opt: T) => Uploader
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import md5 from 'md5'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 递归查找文件
|
|
7
|
+
*/
|
|
8
|
+
export const travelFiles = (dir: string): string[] => {
|
|
9
|
+
const files = fs.readdirSync(dir)
|
|
10
|
+
return files.reduce<string[]>((result, file) => {
|
|
11
|
+
const filePath = path.join(dir, file)
|
|
12
|
+
if (!fs.statSync(filePath).isDirectory()) return [...result, filePath]
|
|
13
|
+
return [...result, ...travelFiles(filePath)]
|
|
14
|
+
}, [])
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 生成文件 key
|
|
19
|
+
*/
|
|
20
|
+
export const generateFileUniqueKey = (filePath: string) => {
|
|
21
|
+
const { dir, base } = path.parse(filePath)
|
|
22
|
+
const buffer = fs.readFileSync(`${dir}${path.sep}${base}`)
|
|
23
|
+
return md5(buffer)
|
|
24
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2015",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"strict": true,
|
|
6
|
+
"sourceMap": true,
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"moduleResolution": "node",
|
|
10
|
+
// 声明文件生成到的文件目录
|
|
11
|
+
"outDir": "./dist/",
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
/* Skip type checking of declaration files. */
|
|
14
|
+
"forceConsistentCasingInFileNames": true,
|
|
15
|
+
"jsx": "react",
|
|
16
|
+
"lib": ["esnext", "dom"],
|
|
17
|
+
"types": ["@types/node"]
|
|
18
|
+
},
|
|
19
|
+
"include": ["src"],
|
|
20
|
+
|
|
21
|
+
}
|