@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 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 项目优化解决方案。
@@ -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,2 @@
1
+ import { UploaderAdapter } from '../types';
2
+ export declare const defineUploaderAdapter: <T>(adapter: UploaderAdapter<T>) => UploaderAdapter<T>;
@@ -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,2 @@
1
+ export * from './upload-adapter-ali-oss';
2
+ export * from './define-adapter';
@@ -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,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/uploader/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 递归查找文件
3
+ */
4
+ export declare const travelFiles: (dir: string) => string[];
5
+ /**
6
+ * 生成文件 key
7
+ */
8
+ export declare const generateFileUniqueKey: (filePath: string) => string;
@@ -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,3 @@
1
+ import { UploaderAdapter } from '../types'
2
+
3
+ export const defineUploaderAdapter = <T>(adapter: UploaderAdapter<T>) => adapter
@@ -0,0 +1,2 @@
1
+ export * from './upload-adapter-ali-oss'
2
+ export * from './define-adapter'
@@ -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
+ }