From d0152283d9426f9ddfe52c97d01c1c7068369c10 Mon Sep 17 00:00:00 2001 From: "xiaohe.wp" Date: Mon, 31 Oct 2022 13:57:23 +0800 Subject: [PATCH 1/7] feat(h5package-opensdk): 0.0.4 --- packages/dingtalk-h5package-opensdk/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/dingtalk-h5package-opensdk/package.json b/packages/dingtalk-h5package-opensdk/package.json index f0b6928..2c80e6c 100644 --- a/packages/dingtalk-h5package-opensdk/package.json +++ b/packages/dingtalk-h5package-opensdk/package.json @@ -1,6 +1,6 @@ { "name": "dingtalk-h5package-opensdk", - "version": "0.0.3", + "version": "0.0.4", "description": "H5离线包OpenSDK", "author": "vularr ", "homepage": "https://github.com/open-dingtalk/dingtalk-design-cli#readme", @@ -27,7 +27,7 @@ "build": "tsc ", "lint": "eslint src", "test": "jest -i", - "prepublishOnly": "npm run lint && npm run build" + "prepublishOnly": "npm run build" }, "bugs": { "url": "https://github.com/open-dingtalk/dingtalk-design-cli/issues" From b673cb0f1efb3c290bf9062d2720312bc6ce6cd9 Mon Sep 17 00:00:00 2001 From: "xiaohe.wp" Date: Thu, 3 Nov 2022 19:03:06 +0800 Subject: [PATCH 2/7] feat(h5package-opensdk): 0.0.5 --- .eslintrc | 3 ++- packages/dingtalk-h5package-opensdk/package.json | 2 +- .../src/cli/h5package.ts | 13 +++++++------ packages/dingtalk-h5package-opensdk/src/index.ts | 15 ++++++++------- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/.eslintrc b/.eslintrc index 9c31f87..10045cf 100644 --- a/.eslintrc +++ b/.eslintrc @@ -17,6 +17,7 @@ "indent": ["error", 2], "semi": "error", "@typescript-eslint/type-annotation-spacing": "error", + "@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/no-unsafe-assignment": 0, "@typescript-eslint/no-var-requires": 0, "quotes": ["error", "single"], @@ -26,7 +27,7 @@ { "arrays": "ignore", "objects": "always", - "imports": "always", + "imports": "only-multiline", "exports": "ignore", "functions": "ignore" } diff --git a/packages/dingtalk-h5package-opensdk/package.json b/packages/dingtalk-h5package-opensdk/package.json index 2c80e6c..9f8de0a 100644 --- a/packages/dingtalk-h5package-opensdk/package.json +++ b/packages/dingtalk-h5package-opensdk/package.json @@ -1,6 +1,6 @@ { "name": "dingtalk-h5package-opensdk", - "version": "0.0.4", + "version": "0.0.5", "description": "H5离线包OpenSDK", "author": "vularr ", "homepage": "https://github.com/open-dingtalk/dingtalk-design-cli#readme", diff --git a/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts b/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts index 0f0da62..9e26bfc 100644 --- a/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts +++ b/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts @@ -5,17 +5,14 @@ async function run(opts: { token: string; appId?: string; agentId?: string; - input?: string; + input: string; + homeUrl?: string; }) { const sdk = new MiniAppOpenSDK(); sdk.setConfig({ accessToken: opts.token }); - const createResult = await sdk.createPackage({ - appId: opts.appId, - agentId: opts.agentId, - input: opts.input, // 在此目录下的所有文件会作为H5离线包的静态资源,压缩上传并创建H5离线包 - }); + const createResult = await sdk.createPackage(opts); await sdk.publishPackage({ appId: opts.appId, @@ -31,12 +28,14 @@ inner .summary('上传企业自建应用离线包资源') .requiredOption('-t, --accesstoken ', '开发者后台apiToken') .requiredOption('-a, --id ', '企业自建应用的agentId') + .requiredOption('-u, --url ', '离线包对应应用的入口地址') .option('-d, --dir ', '要打包上传的离线包资源目录', './') .action(async (options) => { return run({ token: options.accesstoken, agentId: options.id, input: options.dir, + homeUrl: options.url, }); }); @@ -44,12 +43,14 @@ provider .summary('上传第三方企业应用离线包资源') .requiredOption('-t, --accesstoken ', '开发者后台apiToken') .requiredOption('-a, --id ', '企业自建应用的agentId') + .requiredOption('-u, --url ', '离线包对应应用的入口地址') .option('-d, --dir ', '要打包上传的离线包资源目录', './') .action(async (options) => { return run({ token: options.accesstoken, appId: options.id, input: options.dir, + homeUrl: options.url, }); }); diff --git a/packages/dingtalk-h5package-opensdk/src/index.ts b/packages/dingtalk-h5package-opensdk/src/index.ts index 1e5f8f7..43e0dfc 100644 --- a/packages/dingtalk-h5package-opensdk/src/index.ts +++ b/packages/dingtalk-h5package-opensdk/src/index.ts @@ -2,17 +2,18 @@ import archiver from 'archiver'; import fs from 'fs-extra'; import os from 'os'; import path from 'path'; -import { v4 as uuid, } from 'uuid'; +import { v4 as uuid } from 'uuid'; import AliOSS from 'ali-oss'; -import { IGatewayOptions, OpenGateWay, } from './OpenGateway'; +import { IGatewayOptions, OpenGateWay } from './OpenGateway'; export interface ISdkOptions extends IGatewayOptions {} export interface IUploadOptions { - appId: string; - agentId: string; + appId?: string; + agentId?: string; input: string; + homeUrl?: string; } export interface IPublishOptions { @@ -29,13 +30,13 @@ export function packTarGz(dir: string, dist: string) { fs.ensureDirSync(path.dirname(dist)); const output = fs.createWriteStream(dist); - const archive = archiver('tar', { gzip: true, }); + const archive = archiver('tar', { gzip: true }); let size = 0; output.on('close', () => { console.log(archive.pointer() + ' total bytes'); size = archive.pointer(); - resolve({ size, output: dist, }); + resolve({ size, output: dist }); }); output.on('end', () => { console.log('Data has been drained'); @@ -56,7 +57,7 @@ export function packTarGz(dir: string, dist: string) { }); archive.pipe(output); - archive.glob('**', { cwd: dir, }); + archive.glob('**', { cwd: dir }); archive.finalize(); }); } From 9b040eb1f22afcf588de6e98e699c65d323ea78d Mon Sep 17 00:00:00 2001 From: "xiaohe.wp" Date: Mon, 14 Nov 2022 21:23:55 +0800 Subject: [PATCH 3/7] feat(h5package-opensdk): 2.x --- packages/dingtalk-h5package-opensdk/README.md | 122 ++++++++++---- .../__tests__/PackagePacker.spec.ts | 56 +++++++ .../__tests__/source/vendor.js | 5 + .../dingtalk-h5package-opensdk/package.json | 6 +- .../src/PackagePacker.ts | 113 +++++++++++++ .../src/cli/h5package.ts | 113 +++++++------ .../dingtalk-h5package-opensdk/src/index.ts | 158 ++++++------------ 7 files changed, 392 insertions(+), 181 deletions(-) create mode 100644 packages/dingtalk-h5package-opensdk/__tests__/PackagePacker.spec.ts create mode 100644 packages/dingtalk-h5package-opensdk/__tests__/source/vendor.js create mode 100644 packages/dingtalk-h5package-opensdk/src/PackagePacker.ts diff --git a/packages/dingtalk-h5package-opensdk/README.md b/packages/dingtalk-h5package-opensdk/README.md index 8ee13b4..e3a644b 100644 --- a/packages/dingtalk-h5package-opensdk/README.md +++ b/packages/dingtalk-h5package-opensdk/README.md @@ -11,47 +11,113 @@ npm install dingtalk-h5package-opensdk --save-dev ``` -## 用法 -### 命令行用法 +## 快速开始 +
-```javascript +1. 在项目中安装打包SDK -// 企业自建应用 -npx h5package inner --id <企业自建应用agentId> --accesstoken <企业apiToken> --dir ./dist +```bash -// 第三方企业应用 -npx h5package provider --id <第三方企业应用appId> --accesstoken <企业apiToken> --dir ./dist +npm install dingtalk-h5package-opensdk --save-dev + +``` +
+ +2. 在项目根目录下创建离线包资源配置文件localresource.json + +```js +// localresource.json +{ + +} +``` + +3. 在 ```localresource.json``` 中添加 ```assets``` 配置,声明工程构建产物资源与线上资源的映射关系。 +示例: +```js +{ + // key为应用的URL路径地址,值为本地文件或目录 + "assets: { + // 目录 + "https://www.example.com/myapp": "./dist", + // 文件 + "https://www.example.com/myapp/hello.html": "./dist/hello.html" + }, +} ``` +
-### 脚本用法 + 4. 在 ```localresource.json``` 中添加 ```externalAssets``` 配置,声明应用中依赖引入的外部资源(如 react、 react-dom等)。 -```javascript -import { sdk } from 'dingtalk-h5package-opensdk'; +```js +{ + // key为应用的URL路径地址,值为本地文件或目录 + "assets: { + // 目录 + "https://www.example.com/myapp": "./dist", + // 文件 + "https://www.example.com/myapp/hello.html": "./dist/hello.html" + }, + "externalAssets": [ + "https://unpkg.com/react@16.7.0/umd/react.production.min.js" + ] +} + +``` + +5. 在项目package.json中声明打包上传离线包命令: +
+ + +```json +{ + "scripts": { + "create-h5package": "npx h5package --id {离线包ID} --accesstoken {企业apiToken}" + } +} +``` -// 初始化参数 -sdk.setConfig({ - accessToken: '从开放平台获取的apiToken', -}); -// 创建H5离线包 -const { version } = await sdk.createPackage({ - // 应用的ID,二选一即可。 - appId: '第三方企业应用appId', - agentId: '企业内部agentId', - input: 'H5离线包资源所在的目录地址', // 在此目录下的所有文件会作为H5离线包的静态资源,压缩上传并创建H5离线包 -}); +5. 上传离线包 + +```bash +npm run create-h5pacakge +``` -// H5离线包发布上线 -await sdk.publishPackage({ - // 设置应用的ID,二选一即可。 - appId: '第三方企业应用appId', - agentId: '企业内部agentId', - version: version, // 需要发布的离线包的版本号,如0.0.1。 -}); +
+ +### 打包配置文件 Config + +```typescript +{ + // 线上资源URL和本地文件、目录映射关系。key 为线上资源URL地址,值 为本地文件地址。支持 文件 和 目录 + // 示例: + // { + // assets: { + // 键值为目录。将 ./dist 目录下的资源添加到 https://www.example.com/myapp 下 + // "https://www.example.com/myapp": "./dist", + // 键值为文件。将 ./favorite.icon 添加到 https://www.example.com/myapp/favorite.ico + // "https://www.example.com/myapp/favorite.ico": "./favorite.ico", + // } + // } + assets: Record; + // 依赖的外部URL列表。 + // 应用中往往会依赖一些外部资源,如react、vue等外部公共库CDN资源。 + // 添加到此配置后,打包脚本会自动通过HTTP GET请求从网络下载资源内容进行打包。 + // 示例: + // { + // "externalAssets": [ + // "https://unpkg.com/react@16.7.0/umd/react.production.min.js", + // "https://unpkg.com/vue@3.2.45/dist/vue.global.js", + // "https://unpkg.com/jquery@3.6.1/dist/jquery.js" + // ] + // } + externalAssets: string[]; +} ``` diff --git a/packages/dingtalk-h5package-opensdk/__tests__/PackagePacker.spec.ts b/packages/dingtalk-h5package-opensdk/__tests__/PackagePacker.spec.ts new file mode 100644 index 0000000..2c4ad7a --- /dev/null +++ b/packages/dingtalk-h5package-opensdk/__tests__/PackagePacker.spec.ts @@ -0,0 +1,56 @@ +import { PackagePacker, urlToPath, pathToUrl } from '../src/PackagePacker'; +import path from 'path'; + + +describe('PackagePacker', () => { + + it('urlToPath', async () => { + const uc = { + 'https://www.dingtalk.com': 'www.dingtalk.com', + 'https://www.dingtalk.com/': 'www.dingtalk.com', + 'https://www.dingtalk.com/abc': 'www.dingtalk.com/abc', + 'https://www.dingtalk.com/abc/': 'www.dingtalk.com/abc', + 'https://www.dingtalk.com/abc/index.html': 'www.dingtalk.com/abc/index.html', + 'https://www.dingtalk.com:8484/abc/index.html': 'www.dingtalk.com@8484/abc/index.html', + }; + + Object.keys(uc).forEach((url) => { + expect(urlToPath(url)).toBe(uc[url]); + }); + }); + + it('pathToUrl', async () => { + const uc = { + 'www.dingtalk.com': 'https://www.dingtalk.com', + 'www.dingtalk.com/abc': 'https://www.dingtalk.com/abc', + 'www.dingtalk.com/abc/index.html': 'https://www.dingtalk.com/abc/index.html', + 'www.dingtalk.com@8484/abc/index.html': 'https://www.dingtalk.com:8484/abc/index.html', + }; + + Object.keys(uc).forEach((path) => { + expect(pathToUrl(path)).toBe(uc[path]); + }); + }); + + it('appendFile', async () => { + const packer = new PackagePacker(); + await packer.appendFile( + 'https://www.example.com/index.html', + path.join(__dirname, './source/index.html') + ); + await packer.appendFile( + 'https://www.example.com/index.js', + path.join(__dirname, './source/vendor.js') + ); + await packer.appendFile( + 'https://www.example.com/sub', + path.join(__dirname, './source') + ); + await packer.appendUrl( + 'https://g.alicdn.com/code/lib/react/0.0.0-0c756fb-f7f79fd/cjs/react.development.js' + ); + const dist = await packer.finalize(); + + console.log(dist); + }, 60000); +}); diff --git a/packages/dingtalk-h5package-opensdk/__tests__/source/vendor.js b/packages/dingtalk-h5package-opensdk/__tests__/source/vendor.js new file mode 100644 index 0000000..6dd3b07 --- /dev/null +++ b/packages/dingtalk-h5package-opensdk/__tests__/source/vendor.js @@ -0,0 +1,5 @@ + + +function hello(){ + console.log('hello world'); +} \ No newline at end of file diff --git a/packages/dingtalk-h5package-opensdk/package.json b/packages/dingtalk-h5package-opensdk/package.json index 9f8de0a..082bb3e 100644 --- a/packages/dingtalk-h5package-opensdk/package.json +++ b/packages/dingtalk-h5package-opensdk/package.json @@ -1,6 +1,6 @@ { "name": "dingtalk-h5package-opensdk", - "version": "0.0.5", + "version": "2.0.1", "description": "H5离线包OpenSDK", "author": "vularr ", "homepage": "https://github.com/open-dingtalk/dingtalk-design-cli#readme", @@ -17,7 +17,7 @@ "dist" ], "publishConfig": { - "registry": "https://registry.npmjs.org/" + "registry": "https://registry.npmjs.com/" }, "repository": { "type": "git", @@ -45,7 +45,9 @@ "archiver": "^5.3.1", "axios": "^0.27.2", "commander": "^9.4.1", + "download": "^8.0.0", "fs-extra": "^10.1.0", + "uri-js": "^4.4.1", "uuid": "^9.0.0" } } diff --git a/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts b/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts new file mode 100644 index 0000000..ba1b71a --- /dev/null +++ b/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts @@ -0,0 +1,113 @@ +import archiver from 'archiver'; +import fs from 'fs-extra'; +import path from 'path'; +import download from 'download'; + +export interface PackerConfig { + assets: Record; + externalAssets?: string[]; + globMappingRules?: Record; +} + +export function urlToPath(url: string) { + let uri: URL; + + try { + uri = new URL(url); + } catch (error) { + throw new Error(`无效的资源地址: ${url}`); + } + + if (uri.protocol !== 'https:') { + throw new Error(`无效的资源地址: ${url}, 离线包只支持 https 协议`); + } + + const host = uri.port ? `${uri.hostname}@${uri.port}` : uri.hostname; + + let p = `${host}${uri.pathname}`; + + if (p.endsWith('/')) { + p = p.slice(0, -1); + } + + return p; +} + +export function pathToUrl(filename: string) { + const sep = '/'; + const arr = filename.split(sep); + const host = arr[0]; + const pathname = arr.slice(1).join(sep); + + let p = `https://${host.replace('@', ':')}/${pathname}`; + + if (p.endsWith('/')) { + p = p.slice(0, -1); + } + + return p; +} + + +export class PackagePacker { + private arch: archiver.Archiver; + private prom: Promise; + private output: fs.WriteStream; + private file: string; + private bundleMode = 2; + private includeUrlSet = new Set(); + private resourceConfigFileName = 'localresource.json'; + + constructor(readonly options: { + filename: string; + }) { + this.file = path.join(__dirname, options.filename); + this.output = fs.createWriteStream(this.file); + this.arch = archiver('tar', { gzip: true }); + this.prom = new Promise((r, c) => { + this.arch.on('error', c); + this.output.on('close', r); + }); + this.arch.on('entry', (entry) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if ((entry as any).type === 'file' && entry.name !== this.resourceConfigFileName) { + this.includeUrlSet.add(pathToUrl(entry.name)); + } + }); + this.arch.pipe(this.output); + } + + async appendFile(url: string, fileOrDirectory: string) { + const p = path.resolve(fileOrDirectory); + const stat = await fs.stat(p); + const filePath = urlToPath(url); + + if (stat.isDirectory()) { + this.arch.directory(p, filePath); + } else if (stat.isFile()) { + this.arch.file(p, { name: filePath }); + } else { + throw new Error(`无效的文件或目录: ${p}`); + } + } + + async appendUrl(url: string) { + const content = await download(url); + + this.arch.append(content, { name: urlToPath(url) }); + } + + // 暂时不支持 + // async appendGlobMapping(globPartten: string, file: string) {} + + async finalize() { + await this.arch.append(JSON.stringify({ + bundleMode: this.bundleMode, + includeUrls: Array.from(this.includeUrlSet), + globMappingRules: [], + }), { name: this.resourceConfigFileName, }); + await this.arch.finalize(); + return Promise.resolve(this.prom) + .then(() => this.file); + } +} \ No newline at end of file diff --git a/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts b/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts index 9e26bfc..7ea2ca5 100644 --- a/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts +++ b/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts @@ -1,63 +1,82 @@ -import { program, createCommand } from 'commander'; +#!/usr/bin/env node + +import { program } from 'commander'; +import fs from 'fs-extra'; + import { MiniAppOpenSDK } from '../index'; +import { PackagePacker, PackerConfig } from '../PackagePacker'; async function run(opts: { - token: string; - appId?: string; - agentId?: string; - input: string; - homeUrl?: string; + accesstoken: string; + id: string; + config: string; + host?: string; }) { - const sdk = new MiniAppOpenSDK(); + try { + const sdk = new MiniAppOpenSDK(); - sdk.setConfig({ accessToken: opts.token }); + sdk.setConfig({ accessToken: opts.accesstoken, host: opts.host }); - const createResult = await sdk.createPackage(opts); - - await sdk.publishPackage({ - appId: opts.appId, - agentId: opts.agentId, - version: createResult.version, - }); -} + const packer = new PackagePacker({ + filename: `${opts.id}.tar.gz`, + }); -const inner = createCommand('inner'); -const provider = createCommand('provider'); + if (!fs.existsSync(opts.config)) { + throw new Error(`配置文件不存在: ${opts.config}`); + } -inner - .summary('上传企业自建应用离线包资源') - .requiredOption('-t, --accesstoken ', '开发者后台apiToken') - .requiredOption('-a, --id ', '企业自建应用的agentId') - .requiredOption('-u, --url ', '离线包对应应用的入口地址') - .option('-d, --dir ', '要打包上传的离线包资源目录', './') - .action(async (options) => { - return run({ - token: options.accesstoken, - agentId: options.id, - input: options.dir, - homeUrl: options.url, + const config: PackerConfig = await fs.readJson(opts.config, { + throws: true, }); - }); -provider - .summary('上传第三方企业应用离线包资源') - .requiredOption('-t, --accesstoken ', '开发者后台apiToken') - .requiredOption('-a, --id ', '企业自建应用的agentId') - .requiredOption('-u, --url ', '离线包对应应用的入口地址') - .option('-d, --dir ', '要打包上传的离线包资源目录', './') - .action(async (options) => { - return run({ - token: options.accesstoken, - appId: options.id, - input: options.dir, - homeUrl: options.url, + if (!config) { + throw new Error(`配置文件格式错误: ${opts.config}`); + } + + const { assets = {}, externalAssets = [] } = config; + const assetKeys = Object.keys(assets); + + for (const assetKey of assetKeys) { + await packer.appendFile(assetKey, assets[assetKey]); + } + + for (const externalAsset of externalAssets) { + await packer.appendUrl(externalAsset); + } + + const file = await packer.finalize(); + + const createResult = await sdk.createPackage({ + miniAppId: opts.id, + file, }); - }); + await sdk.publishPackage({ + miniAppId: opts.id, + version: createResult.version, + }); + } catch (error) { + console.error(error); + } +} + program + .summary('上传应用离线包资源') .name('h5package') - .version('0.0.1', '-v, --version', 'output the current version') - .addCommand(inner) - .addCommand(provider); + .version('2.0.0', '-v, --version', 'output the current version') + .requiredOption('-t, --accesstoken ', '开发者后台apiToken') + .requiredOption('-i, --id ', '离线包ID') + .option('-h, --host ', '网关域名') + .option('-c, --config ', '打包配置', './localresource.json') + .action( + async (options: { + accesstoken: string; + id: string; + config: string; + host?: string; + }) => { + return run(options); + } + ); program.parseAsync(); diff --git a/packages/dingtalk-h5package-opensdk/src/index.ts b/packages/dingtalk-h5package-opensdk/src/index.ts index 43e0dfc..429cb0f 100644 --- a/packages/dingtalk-h5package-opensdk/src/index.ts +++ b/packages/dingtalk-h5package-opensdk/src/index.ts @@ -1,8 +1,3 @@ -import archiver from 'archiver'; -import fs from 'fs-extra'; -import os from 'os'; -import path from 'path'; -import { v4 as uuid } from 'uuid'; import AliOSS from 'ali-oss'; import { IGatewayOptions, OpenGateWay } from './OpenGateway'; @@ -10,63 +5,20 @@ import { IGatewayOptions, OpenGateWay } from './OpenGateway'; export interface ISdkOptions extends IGatewayOptions {} export interface IUploadOptions { - appId?: string; - agentId?: string; - input: string; - homeUrl?: string; + miniAppId: string; + file: string; } export interface IPublishOptions { - appId: string; - agentId: string; + miniAppId: string; version: string; } -export function packTarGz(dir: string, dist: string) { - return new Promise<{ - size: number; - output: string; - }>((resolve, reject) => { - fs.ensureDirSync(path.dirname(dist)); - - const output = fs.createWriteStream(dist); - const archive = archiver('tar', { gzip: true }); - let size = 0; - - output.on('close', () => { - console.log(archive.pointer() + ' total bytes'); - size = archive.pointer(); - resolve({ size, output: dist }); - }); - output.on('end', () => { - console.log('Data has been drained'); - }); - - // good practice to catch warnings (ie stat failures and other non-blocking errors) - archive.on('warning', (err) => { - if (err.code === 'ENOENT') { - // log warning - } else { - // throw error - throw err; - } - }); - - archive.on('error', (err) => { - reject(err); - }); - - archive.pipe(output); - archive.glob('**', { cwd: dir }); - archive.finalize(); - }); -} - const enum OpenApiAction { - GetUploadToken = '/v1.0/h5package/uploadTokens', - UploadPackage = '/v1.0/h5package/asyncUpload', - GetUploadStatus = '/v1.0/h5package/uploadStatus', - Publish = 'v1.0/h5package/publish', + GetUploadToken = '/v1.0/package/uploadTokens', + UploadPackage = '/v1.0/package/h5/upload', + GetUploadStatus = '/v1.0/package/h5/uploadStatus', + Publish = 'v1.0/package/h5/publish', } export interface IGetUploadTokenResult { @@ -106,59 +58,60 @@ export class MiniAppOpenSDK { this.gateway = new OpenGateWay(sdkConfig); } - private async pollingCreateStatusWhenFinished( - taskId: string, - beginTime: number, - maxTimeoutLimit: number - ): Promise { + private async pollingCreateStatusWhenFinished(opts: { + miniAppId: string; + taskId: string; + beginTime: number; + maxTimeoutLimit: number; + }): Promise { const createStatus = await this.gateway.request( 'GET', OpenApiAction.GetUploadStatus, { - taskId, + miniAppId: opts.miniAppId, + taskId: opts.taskId, } ); switch (createStatus.status) { - case CreateStatus.Packing: { - const now = Date.now(); - const costTime = now - beginTime; - - if (costTime > maxTimeoutLimit) { - throw new Error('create package timeout'); - } - - console.log('create task is doing, query task status 10s later'); - return new Promise((r, c) => { - setTimeout(() => { - this.pollingCreateStatusWhenFinished( - taskId, - beginTime, - maxTimeoutLimit - ).then(r, c); - }, 10 * 1000); - }); - } - case CreateStatus.Success: { - console.log('create task is finished'); - console.log(createStatus); - return createStatus; - } - case CreateStatus.Failed: { - throw new Error('create package failed'); - } - case CreateStatus.Timeout: { - throw new Error('create package timeout, please try again'); - } - default: { - throw new Error(`unknown create status: ${createStatus.status}`); + + case CreateStatus.Packing: { + const now = Date.now(); + const costTime = now - opts.beginTime; + + if (costTime > opts.maxTimeoutLimit) { + throw new Error('create package timeout'); } + + // eslint-disable-next-line no-console + console.log('create task is doing, query task status 10s later'); + return new Promise((r, c) => { + setTimeout(() => { + this.pollingCreateStatusWhenFinished({ ...opts, }).then(r, c); + }, 10 * 1000); + }); + } + case CreateStatus.Success: { + // eslint-disable-next-line no-console + console.log('create task is finished', createStatus); + return createStatus; + } + case CreateStatus.Failed: { + throw new Error('create package failed'); + } + case CreateStatus.Timeout: { + throw new Error('create package timeout, please try again'); + } + default: { + throw new Error(`unknown create status: ${createStatus.status}`); + } + } } public async createPackage(options: IUploadOptions) { const maxTimeoutLimit = 1000 * 60 * 5; // 5 minutes - const { input, ...commonParamenters } = options; + const { file, ...commonParamenters } = options; const { name, ...ossConfig } = await this.gateway.request( 'GET', @@ -170,11 +123,7 @@ export class MiniAppOpenSDK { secure: true, }); - const packResult = await packTarGz( - input, - path.join(os.tmpdir(), `${uuid()}.tar.gz`) - ); - await ossClient.put(name, packResult.output); + await ossClient.put(name, file); const createResult = await this.gateway.request( 'POST', OpenApiAction.UploadPackage, @@ -185,11 +134,12 @@ export class MiniAppOpenSDK { } ); - const packageInfo = await this.pollingCreateStatusWhenFinished( - createResult.taskId, - Date.now(), - maxTimeoutLimit - ); + const packageInfo = await this.pollingCreateStatusWhenFinished({ + ...commonParamenters, + taskId: createResult.taskId, + beginTime: Date.now(), + maxTimeoutLimit, + }); return packageInfo; } From 8ce25d2c31da7ba7a2462df2fb71d3ca228e8422 Mon Sep 17 00:00:00 2001 From: "xiaohe.wp" Date: Mon, 21 Nov 2022 20:08:22 +0800 Subject: [PATCH 4/7] =?UTF-8?q?feat(h5package-opensdk):=20=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E8=A1=8C=E6=96=B9=E5=BC=8F=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/dingtalk-h5package-opensdk/README.md | 64 ++++++-- .../dingtalk-h5package-opensdk/package.json | 3 +- .../src/PackagePacker.ts | 34 +++-- .../src/cli/h5package.ts | 138 ++++++++++++------ .../dingtalk-h5package-opensdk/src/index.ts | 4 +- 5 files changed, 173 insertions(+), 70 deletions(-) diff --git a/packages/dingtalk-h5package-opensdk/README.md b/packages/dingtalk-h5package-opensdk/README.md index e3a644b..e06c555 100644 --- a/packages/dingtalk-h5package-opensdk/README.md +++ b/packages/dingtalk-h5package-opensdk/README.md @@ -12,11 +12,10 @@ npm install dingtalk-h5package-opensdk --save-dev ``` - ## 快速开始
-1. 在项目中安装打包SDK +1\. 在项目中安装打包OpenSDK ```bash @@ -25,16 +24,17 @@ npm install dingtalk-h5package-opensdk --save-dev ```
-2. 在项目根目录下创建离线包资源配置文件localresource.json +2\. 在项目根目录下创建离线包资源配置文件 ```localresource.json```,声明离线包ID、[开放平台网关ApiToken](https://open.dingtalk.com/document/orgapp-server/used-to-obtain-the-application-authorization-without-api-token) ```js // localresource.json { - + "miniAppId": "离线包ID", + "accessToken": "开放平台网关ApiToken" } ``` -3. 在 ```localresource.json``` 中添加 ```assets``` 配置,声明工程构建产物资源与线上资源的映射关系。 +3\. 在 ```localresource.json``` 中添加 ```assets``` 配置,声明项目中静态资源(编译产物、静态资源皆可)与线上资源的映射关系。 示例: @@ -52,17 +52,10 @@ npm install dingtalk-h5package-opensdk --save-dev
- 4. 在 ```localresource.json``` 中添加 ```externalAssets``` 配置,声明应用中依赖引入的外部资源(如 react、 react-dom等)。 + 4\. 在 ```localresource.json``` 中添加 ```externalAssets``` 配置,声明应用中依赖的外部资源(如 react、 react-dom等)。 ```js { - // key为应用的URL路径地址,值为本地文件或目录 - "assets: { - // 目录 - "https://www.example.com/myapp": "./dist", - // 文件 - "https://www.example.com/myapp/hello.html": "./dist/hello.html" - }, "externalAssets": [ "https://unpkg.com/react@16.7.0/umd/react.production.min.js" ] @@ -77,7 +70,7 @@ npm install dingtalk-h5package-opensdk --save-dev ```json { "scripts": { - "create-h5package": "npx h5package --id {离线包ID} --accesstoken {企业apiToken}" + "create-h5package": "npx h5package packAndDeploy" } } ``` @@ -90,12 +83,55 @@ npm run create-h5pacakge ``` +## 命令列表 + + +### pack + +本地离线包资源打包,在本地输出打包后的离线资源文件,文件格式为.tar.gz。离线包ID自动在 ```localresource.json``` 文件中查找。 + +用法: + +```bash + +npx h5package pack + +``` + +### deploy + +将指定版本的H5离线包发布到线上。离线包ID和accessToken自动在 ```localresource.json``` 文件中查找。 + +用法: +```bash + +npx h5package deploy + +``` + + +### packAndDeploy + +打包离线包资源,上传并发布到线上。离线包ID和打包配置自动在 ```localresource.json``` 文件中查找。 + +```bash + +npx h5package packAndDeploy + +``` + + +
### 打包配置文件 Config ```typescript { + // 离线包ID + miniAppId: string; + // 访问凭证API TOKEN。上传请求开放平台网关时需要。 + accessToken: string; // 线上资源URL和本地文件、目录映射关系。key 为线上资源URL地址,值 为本地文件地址。支持 文件 和 目录 // 示例: // { diff --git a/packages/dingtalk-h5package-opensdk/package.json b/packages/dingtalk-h5package-opensdk/package.json index 082bb3e..4d8126b 100644 --- a/packages/dingtalk-h5package-opensdk/package.json +++ b/packages/dingtalk-h5package-opensdk/package.json @@ -1,6 +1,6 @@ { "name": "dingtalk-h5package-opensdk", - "version": "2.0.1", + "version": "2.0.4", "description": "H5离线包OpenSDK", "author": "vularr ", "homepage": "https://github.com/open-dingtalk/dingtalk-design-cli#readme", @@ -47,6 +47,7 @@ "commander": "^9.4.1", "download": "^8.0.0", "fs-extra": "^10.1.0", + "glob": "^8.0.3", "uri-js": "^4.4.1", "uuid": "^9.0.0" } diff --git a/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts b/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts index ba1b71a..aa377d9 100644 --- a/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts +++ b/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts @@ -2,8 +2,12 @@ import archiver from 'archiver'; import fs from 'fs-extra'; import path from 'path'; import download from 'download'; +import glob from 'glob'; export interface PackerConfig { + host?: string; + miniAppId: string; + accessToken: string; assets: Record; externalAssets?: string[]; globMappingRules?: Record; @@ -61,36 +65,43 @@ export class PackagePacker { constructor(readonly options: { filename: string; }) { - this.file = path.join(__dirname, options.filename); + this.file = path.join(process.cwd(), options.filename); this.output = fs.createWriteStream(this.file); this.arch = archiver('tar', { gzip: true }); this.prom = new Promise((r, c) => { this.arch.on('error', c); this.output.on('close', r); }); - this.arch.on('entry', (entry) => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if ((entry as any).type === 'file' && entry.name !== this.resourceConfigFileName) { - this.includeUrlSet.add(pathToUrl(entry.name)); - } - }); this.arch.pipe(this.output); } async appendFile(url: string, fileOrDirectory: string) { const p = path.resolve(fileOrDirectory); const stat = await fs.stat(p); - const filePath = urlToPath(url); - if (stat.isDirectory()) { - this.arch.directory(p, filePath); + if (stat.isDirectory()) { + await this.appendDirectory(url, p); } else if (stat.isFile()) { - this.arch.file(p, { name: filePath }); + this.arch.file(p, { name: urlToPath(url), }); } else { throw new Error(`无效的文件或目录: ${p}`); } } + async appendDirectory(url: string, directory: string) { + const prefixURL = new URL(url); + const prefixPathname = prefixURL.pathname; + const files = glob.sync('**/*', { cwd: directory, nodir: true, }); + + for (const file of files) { + const fullPathname = path.join(prefixPathname, file); + const fullUrl = new URL(fullPathname, prefixURL.origin).toString(); + + this.arch.file(path.join(directory, file), { name: urlToPath(fullUrl), }); + this.includeUrlSet.add(fullUrl); + } + } + async appendUrl(url: string) { const content = await download(url); @@ -106,6 +117,7 @@ export class PackagePacker { includeUrls: Array.from(this.includeUrlSet), globMappingRules: [], }), { name: this.resourceConfigFileName, }); + await this.arch.finalize(); return Promise.resolve(this.prom) .then(() => this.file); diff --git a/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts b/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts index 7ea2ca5..3285869 100644 --- a/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts +++ b/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts @@ -6,6 +6,39 @@ import fs from 'fs-extra'; import { MiniAppOpenSDK } from '../index'; import { PackagePacker, PackerConfig } from '../PackagePacker'; +async function readResourceConfig(opts: { config: string }) { + if (!fs.existsSync(opts.config)) { + throw new Error(`配置文件不存在: ${opts.config}`); + } + + const config: PackerConfig = await fs.readJson(opts.config, { + throws: true, + }); + + return config; +} + +async function pack(opts: { filename: string; config: PackerConfig }) { + const packer = new PackagePacker({ + filename: opts.filename, + }); + + const { assets = {}, externalAssets = [] } = opts.config; + const assetKeys = Object.keys(assets); + + for (const assetKey of assetKeys) { + await packer.appendFile(assetKey, assets[assetKey]); + } + + for (const externalAsset of externalAssets) { + await packer.appendUrl(externalAsset); + } + + const file = await packer.finalize(); + + return file; +} + async function run(opts: { accesstoken: string; id: string; @@ -13,70 +46,91 @@ async function run(opts: { host?: string; }) { try { + const config = await readResourceConfig(opts); + const miniAppId = opts.id || config.miniAppId; + const host = opts.host || config.host; + const accessToken = opts.accesstoken || config.accessToken; const sdk = new MiniAppOpenSDK(); - sdk.setConfig({ accessToken: opts.accesstoken, host: opts.host }); - - const packer = new PackagePacker({ - filename: `${opts.id}.tar.gz`, - }); - - if (!fs.existsSync(opts.config)) { - throw new Error(`配置文件不存在: ${opts.config}`); - } - - const config: PackerConfig = await fs.readJson(opts.config, { - throws: true, + sdk.setConfig({ + accessToken, + host, }); if (!config) { throw new Error(`配置文件格式错误: ${opts.config}`); } - const { assets = {}, externalAssets = [] } = config; - const assetKeys = Object.keys(assets); - - for (const assetKey of assetKeys) { - await packer.appendFile(assetKey, assets[assetKey]); - } - - for (const externalAsset of externalAssets) { - await packer.appendUrl(externalAsset); - } - - const file = await packer.finalize(); + const file = await pack({ + filename: `${opts.id}.tar.gz`, + config, + }); const createResult = await sdk.createPackage({ - miniAppId: opts.id, + miniAppId, file, }); await sdk.publishPackage({ - miniAppId: opts.id, + miniAppId, version: createResult.version, }); } catch (error) { console.error(error); } } - + program .summary('上传应用离线包资源') - .name('h5package') .version('2.0.0', '-v, --version', 'output the current version') - .requiredOption('-t, --accesstoken ', '开发者后台apiToken') - .requiredOption('-i, --id ', '离线包ID') + .addHelpCommand('help', 'display help for command'); + +program + .command('pack') + .description('打离包线包') + .option('--config ', '打包配置', './localresource.json') + .action(async function (opts) { + const config = await readResourceConfig(opts); + const file = await pack({ + filename: `${config.miniAppId}.tar.gz`, + config, + }); + + console.log('打包完成: %s', file); + }); + +program + .command('deploy', '发布离线包到线上') + .argument('', '离线包版本') + .option('--id ', '离线包ID') + .option('--host ', '网关域名') + .option('--config ', '打包配置', './localresource.json') + .action(async function (version: string) { + const config = await readResourceConfig(this.opts()); + const sdk = new MiniAppOpenSDK(); + + sdk.setConfig({ + accessToken: config.accessToken, + host: config.host, + }); + + const result = await sdk.publishPackage({ + miniAppId: config.miniAppId, + version, + }); + + console.log('发布成功: %o', result); + }); + +program + .command('packAndDeploy') + .description('打包并发布离线包') + .option('-t, --accesstoken ', '开发者后台apiToken') + .option('-i, --id ', '离线包ID') .option('-h, --host ', '网关域名') - .option('-c, --config ', '打包配置', './localresource.json') - .action( - async (options: { - accesstoken: string; - id: string; - config: string; - host?: string; - }) => { - return run(options); - } - ); + .option('--config ', '打包配置', './localresource.json') + .action(async function () { + await run(this.opts()); + }); -program.parseAsync(); +program.parseAsync(process.argv); diff --git a/packages/dingtalk-h5package-opensdk/src/index.ts b/packages/dingtalk-h5package-opensdk/src/index.ts index 429cb0f..7045831 100644 --- a/packages/dingtalk-h5package-opensdk/src/index.ts +++ b/packages/dingtalk-h5package-opensdk/src/index.ts @@ -16,7 +16,7 @@ export interface IPublishOptions { const enum OpenApiAction { GetUploadToken = '/v1.0/package/uploadTokens', - UploadPackage = '/v1.0/package/h5/upload', + UploadPackage = '/v1.0/package/h5/asyncUpload', GetUploadStatus = '/v1.0/package/h5/uploadStatus', Publish = 'v1.0/package/h5/publish', } @@ -84,7 +84,7 @@ export class MiniAppOpenSDK { } // eslint-disable-next-line no-console - console.log('create task is doing, query task status 10s later'); + console.log('uploading, query task status 10s later'); return new Promise((r, c) => { setTimeout(() => { this.pollingCreateStatusWhenFinished({ ...opts, }).then(r, c); From 03fdbde50e56a8246257bbeee25c458f2aca8a0f Mon Sep 17 00:00:00 2001 From: "xiaohe.wp" Date: Tue, 22 Nov 2022 11:58:50 +0800 Subject: [PATCH 5/7] =?UTF-8?q?feat(h5package-opensdk):=202.0.5=EF=BC=8C?= =?UTF-8?q?=E6=89=93=E5=8C=85=E6=A8=A1=E5=9D=97=E5=A2=9E=E5=8A=A0=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E8=B7=AF=E5=BE=84=E9=95=BF=E5=BA=A6=E9=99=90=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dingtalk-h5package-opensdk/package.json | 2 +- .../src/PackagePacker.ts | 44 +++++++++++++++---- .../src/cli/h5package.ts | 4 +- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/packages/dingtalk-h5package-opensdk/package.json b/packages/dingtalk-h5package-opensdk/package.json index 4d8126b..9a9b205 100644 --- a/packages/dingtalk-h5package-opensdk/package.json +++ b/packages/dingtalk-h5package-opensdk/package.json @@ -1,6 +1,6 @@ { "name": "dingtalk-h5package-opensdk", - "version": "2.0.4", + "version": "2.0.5", "description": "H5离线包OpenSDK", "author": "vularr ", "homepage": "https://github.com/open-dingtalk/dingtalk-design-cli#readme", diff --git a/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts b/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts index aa377d9..3f11e59 100644 --- a/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts +++ b/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts @@ -4,6 +4,9 @@ import path from 'path'; import download from 'download'; import glob from 'glob'; +// 文件路径最大长度是100,扣除"web_assets/"目录,实际最大长度是89; +export const MAX_PATH_LENGTH = 88; + export interface PackerConfig { host?: string; miniAppId: string; @@ -69,8 +72,15 @@ export class PackagePacker { this.output = fs.createWriteStream(this.file); this.arch = archiver('tar', { gzip: true }); this.prom = new Promise((r, c) => { - this.arch.on('error', c); - this.output.on('close', r); + this.arch.on('error', err =>{ + console.error('打包失败', err); + c(err); + }); + this.output.on('close', () =>{ + // eslint-disable-next-line no-console + console.log('打包完成', this.file); + r(); + }); }); this.arch.pipe(this.output); } @@ -82,23 +92,41 @@ export class PackagePacker { if (stat.isDirectory()) { await this.appendDirectory(url, p); } else if (stat.isFile()) { - this.arch.file(p, { name: urlToPath(url), }); + this._file(url, p); } else { throw new Error(`无效的文件或目录: ${p}`); } } + private _file(url: string, filename: string) { + const fullFilePath = urlToPath(url); + + if (fullFilePath.length > MAX_PATH_LENGTH) { + console.warn( + `以下文件被忽略,原因:文件路径过长(>${MAX_PATH_LENGTH}): ${path.relative( + process.cwd(), + filename, + )}` + ); + return; + } + + this.arch.file(filename, { name: fullFilePath, }); + this.includeUrlSet.add(url); + } + async appendDirectory(url: string, directory: string) { const prefixURL = new URL(url); - const prefixPathname = prefixURL.pathname; const files = glob.sync('**/*', { cwd: directory, nodir: true, }); for (const file of files) { - const fullPathname = path.join(prefixPathname, file); - const fullUrl = new URL(fullPathname, prefixURL.origin).toString(); + const filename = path.join(directory, file); + const fullUrl = new URL( + path.join(prefixURL.pathname, file), + prefixURL.origin + ).toString(); - this.arch.file(path.join(directory, file), { name: urlToPath(fullUrl), }); - this.includeUrlSet.add(fullUrl); + this._file(fullUrl, filename); } } diff --git a/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts b/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts index 3285869..83ed3c6 100644 --- a/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts +++ b/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts @@ -91,12 +91,10 @@ program .option('--config ', '打包配置', './localresource.json') .action(async function (opts) { const config = await readResourceConfig(opts); - const file = await pack({ + await pack({ filename: `${config.miniAppId}.tar.gz`, config, }); - - console.log('打包完成: %s', file); }); program From 9687bd86f3d23e76381254758890e03a79f1c54e Mon Sep 17 00:00:00 2001 From: "xiaohe.wp" Date: Tue, 22 Nov 2022 19:10:09 +0800 Subject: [PATCH 6/7] =?UTF-8?q?feat(h5package-opensdk):=202.0.6=EF=BC=8C?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=88=90=E5=8A=9F=E5=90=8E=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E4=B8=B4=E6=97=B6=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/dingtalk-h5package-opensdk/package.json | 2 +- packages/dingtalk-h5package-opensdk/src/PackagePacker.ts | 2 +- packages/dingtalk-h5package-opensdk/src/cli/h5package.ts | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/dingtalk-h5package-opensdk/package.json b/packages/dingtalk-h5package-opensdk/package.json index 9a9b205..53d68f2 100644 --- a/packages/dingtalk-h5package-opensdk/package.json +++ b/packages/dingtalk-h5package-opensdk/package.json @@ -1,6 +1,6 @@ { "name": "dingtalk-h5package-opensdk", - "version": "2.0.5", + "version": "2.0.6", "description": "H5离线包OpenSDK", "author": "vularr ", "homepage": "https://github.com/open-dingtalk/dingtalk-design-cli#readme", diff --git a/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts b/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts index 3f11e59..e7834c0 100644 --- a/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts +++ b/packages/dingtalk-h5package-opensdk/src/PackagePacker.ts @@ -103,7 +103,7 @@ export class PackagePacker { if (fullFilePath.length > MAX_PATH_LENGTH) { console.warn( - `以下文件被忽略,原因:文件路径过长(>${MAX_PATH_LENGTH}): ${path.relative( + `以下文件被忽略(文件路径长度>${MAX_PATH_LENGTH}): ${path.relative( process.cwd(), filename, )}` diff --git a/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts b/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts index 83ed3c6..db30f3b 100644 --- a/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts +++ b/packages/dingtalk-h5package-opensdk/src/cli/h5package.ts @@ -62,7 +62,7 @@ async function run(opts: { } const file = await pack({ - filename: `${opts.id}.tar.gz`, + filename: `${miniAppId}.tar.gz`, config, }); @@ -75,6 +75,8 @@ async function run(opts: { miniAppId, version: createResult.version, }); + + await fs.remove(file); } catch (error) { console.error(error); } From 901865698df3c257eb341f58d8c2d8b0f2ea32c2 Mon Sep 17 00:00:00 2001 From: "xiaohe.wp" Date: Tue, 22 Nov 2022 20:57:42 +0800 Subject: [PATCH 7/7] feat(h5package-opensdk): 2.0.7 --- packages/dingtalk-h5package-opensdk/README.md | 158 ------------------ .../dingtalk-h5package-opensdk/package.json | 2 +- 2 files changed, 1 insertion(+), 159 deletions(-) diff --git a/packages/dingtalk-h5package-opensdk/README.md b/packages/dingtalk-h5package-opensdk/README.md index e06c555..6cf90b0 100644 --- a/packages/dingtalk-h5package-opensdk/README.md +++ b/packages/dingtalk-h5package-opensdk/README.md @@ -1,159 +1 @@ # `dingtalk-h5package-opensdk` - -> H5离线包OpenSDK - - -## 安装 - -``` - -npm install dingtalk-h5package-opensdk --save-dev - -``` - - -## 快速开始 -
- -1\. 在项目中安装打包OpenSDK - -```bash - -npm install dingtalk-h5package-opensdk --save-dev - -``` -
- -2\. 在项目根目录下创建离线包资源配置文件 ```localresource.json```,声明离线包ID、[开放平台网关ApiToken](https://open.dingtalk.com/document/orgapp-server/used-to-obtain-the-application-authorization-without-api-token) - -```js -// localresource.json -{ - "miniAppId": "离线包ID", - "accessToken": "开放平台网关ApiToken" -} -``` - -3\. 在 ```localresource.json``` 中添加 ```assets``` 配置,声明项目中静态资源(编译产物、静态资源皆可)与线上资源的映射关系。 - -示例: - -```js -{ - // key为应用的URL路径地址,值为本地文件或目录 - "assets: { - // 目录 - "https://www.example.com/myapp": "./dist", - // 文件 - "https://www.example.com/myapp/hello.html": "./dist/hello.html" - }, -} -``` - -
- - 4\. 在 ```localresource.json``` 中添加 ```externalAssets``` 配置,声明应用中依赖的外部资源(如 react、 react-dom等)。 - -```js -{ - "externalAssets": [ - "https://unpkg.com/react@16.7.0/umd/react.production.min.js" - ] -} - -``` - -5. 在项目package.json中声明打包上传离线包命令: -
- - -```json -{ - "scripts": { - "create-h5package": "npx h5package packAndDeploy" - } -} -``` - - -5. 上传离线包 - -```bash -npm run create-h5pacakge -``` - - -## 命令列表 - - -### pack - -本地离线包资源打包,在本地输出打包后的离线资源文件,文件格式为.tar.gz。离线包ID自动在 ```localresource.json``` 文件中查找。 - -用法: - -```bash - -npx h5package pack - -``` - -### deploy - -将指定版本的H5离线包发布到线上。离线包ID和accessToken自动在 ```localresource.json``` 文件中查找。 - -用法: -```bash - -npx h5package deploy - -``` - - -### packAndDeploy - -打包离线包资源,上传并发布到线上。离线包ID和打包配置自动在 ```localresource.json``` 文件中查找。 - -```bash - -npx h5package packAndDeploy - -``` - - - -
- -### 打包配置文件 Config - -```typescript -{ - // 离线包ID - miniAppId: string; - // 访问凭证API TOKEN。上传请求开放平台网关时需要。 - accessToken: string; - // 线上资源URL和本地文件、目录映射关系。key 为线上资源URL地址,值 为本地文件地址。支持 文件 和 目录 - // 示例: - // { - // assets: { - // 键值为目录。将 ./dist 目录下的资源添加到 https://www.example.com/myapp 下 - // "https://www.example.com/myapp": "./dist", - // 键值为文件。将 ./favorite.icon 添加到 https://www.example.com/myapp/favorite.ico - // "https://www.example.com/myapp/favorite.ico": "./favorite.ico", - // } - // } - assets: Record; - // 依赖的外部URL列表。 - // 应用中往往会依赖一些外部资源,如react、vue等外部公共库CDN资源。 - // 添加到此配置后,打包脚本会自动通过HTTP GET请求从网络下载资源内容进行打包。 - // 示例: - // { - // "externalAssets": [ - // "https://unpkg.com/react@16.7.0/umd/react.production.min.js", - // "https://unpkg.com/vue@3.2.45/dist/vue.global.js", - // "https://unpkg.com/jquery@3.6.1/dist/jquery.js" - // ] - // } - externalAssets: string[]; -} -``` diff --git a/packages/dingtalk-h5package-opensdk/package.json b/packages/dingtalk-h5package-opensdk/package.json index 53d68f2..7dd11d3 100644 --- a/packages/dingtalk-h5package-opensdk/package.json +++ b/packages/dingtalk-h5package-opensdk/package.json @@ -1,6 +1,6 @@ { "name": "dingtalk-h5package-opensdk", - "version": "2.0.6", + "version": "2.0.7", "description": "H5离线包OpenSDK", "author": "vularr ", "homepage": "https://github.com/open-dingtalk/dingtalk-design-cli#readme",