Skip to content

Commit 7b85a35

Browse files
authored
feat: zip publisher support browser (alibaba#2744)
1 parent b2abb67 commit 7b85a35

File tree

5 files changed

+74
-14
lines changed

5 files changed

+74
-14
lines changed

modules/code-generator/README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,26 @@ await CodeGenerator.init();
9494
4. 出码
9595

9696
```js
97-
const result = await CodeGenerator.generateCode({
97+
const project = await CodeGenerator.generateCode({
9898
solution: 'icejs', // 出码方案 (目前内置有 icejs 和 rax )
9999
schema, // 编排搭建出来的 schema
100100
});
101101

102-
console.log(result); // 出码结果(默认是递归结构描述的,可以传 flattenResult: true 以生成扁平结构的结果)
102+
console.log(project); // 出码结果(默认是递归结构描述的,可以传 flattenResult: true 以生成扁平结构的结果)
103103
```
104104

105105
注:一般来说在浏览器中出码适合做即时预览功能。
106106

107+
5. 下载 zip 包
108+
109+
```js
110+
// 写入到 zip 包
111+
await CodeGenerator.publishers.zip().publish({
112+
project, // 上一步生成的 project
113+
projectSlug: 'your-project-slug', // 项目标识 -- 对应下载 your-project-slug.zip 文件
114+
});
115+
```
116+
107117
### 5)自定义出码
108118

109119
前端框架灵活多变,默认内置的出码方案很难满足所有人的需求,好在此代码生成器支持非常灵活的插件机制 -- 欢迎参考 ./src/plugins/xxx 来编写您自己的出码插件,然后参考 ./src/solutions/xxx 将各种插件组合成一套适合您的业务场景的出码方案。

modules/code-generator/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
"change-case": "^3.1.0",
8181
"commander": "^6.1.0",
8282
"debug": "^4.3.2",
83+
"file-saver": "^2.0.5",
8384
"fp-ts": "^2.11.9",
8485
"fs-extra": "9.x",
8586
"glob": "^7.2.0",
@@ -109,6 +110,7 @@
109110
"devDependencies": {
110111
"@iceworks/spec": "^1.4.2",
111112
"@types/babel__traverse": "^7.11.0",
113+
"@types/file-saver": "^2.0.7",
112114
"@types/jest": "^27.0.2",
113115
"@types/lodash": "^4.14.162",
114116
"@types/node": "^14.14.20",

modules/code-generator/src/publisher/zip/index.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { ResultDir } from '@alilc/lowcode-types';
22
import { PublisherFactory, IPublisher, IPublisherFactoryParams, PublisherError } from '../../types';
33
import { getErrorMessage } from '../../utils/errors';
44
import { isNodeProcess, writeZipToDisk, generateProjectZip } from './utils';
5+
import { saveAs } from 'file-saver';
56

6-
// export type ZipBuffer = Buffer | Blob;
7-
export type ZipBuffer = Buffer;
7+
export type ZipBuffer = Buffer | Blob;
88

99
declare type ZipPublisherResponse = string | ZipBuffer;
1010

@@ -44,10 +44,16 @@ export const createZipPublisher: PublisherFactory<ZipFactoryParams, ZipPublisher
4444
try {
4545
const zipContent = await generateProjectZip(projectToPublish);
4646

47-
// If not output path is provided, zip is not written to disk
48-
const projectOutputPath = options.outputPath || outputPath;
49-
if (projectOutputPath && isNodeProcess()) {
50-
await writeZipToDisk(projectOutputPath, zipContent, zipName);
47+
if (isNodeProcess()) {
48+
// If not output path is provided on the node side, zip is not written to disk
49+
const projectOutputPath = options.outputPath || outputPath;
50+
if (projectOutputPath) {
51+
await writeZipToDisk(projectOutputPath, zipContent, zipName);
52+
}
53+
} else {
54+
// the browser end does not require a path
55+
// auto download zip files
56+
saveAs(zipContent as Blob, `${zipName}.zip`);
5157
}
5258

5359
return { success: true, payload: zipContent };

modules/code-generator/src/publisher/zip/utils.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ export const writeZipToDisk = (
4040
export const generateProjectZip = async (project: ResultDir): Promise<ZipBuffer> => {
4141
let zip = new JSZip();
4242
zip = writeFolderToZip(project, zip, true);
43-
// const zipType = isNodeProcess() ? 'nodebuffer' : 'blob';
44-
const zipType = 'nodebuffer'; // 目前先只支持 node 调用
43+
const zipType = isNodeProcess() ? 'nodebuffer' : 'blob';
4544
return zip.generateAsync({ type: zipType });
4645
};
4746

modules/code-generator/tests/public/publisher/zip/zip.test.ts

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import CodeGen from '../../../../src';
2+
import fileSaver from 'file-saver';
3+
import * as utils from '../../../../src/publisher/zip/utils';
4+
5+
jest.mock('file-saver');
26

37
describe('public/publisher/zip/zip', () => {
8+
afterEach(() => {
9+
jest.clearAllMocks();
10+
});
11+
412
it('should works', async () => {
513
const zip = CodeGen.publishers.zip({
614
outputPath: 'demo-output',
@@ -19,15 +27,15 @@ describe('public/publisher/zip/zip', () => {
1927
],
2028
};
2129

22-
expect(zip.getOutputPath()).toMatchInlineSnapshot(`"demo-output"`);
30+
expect(zip.getOutputPath()).toMatchInlineSnapshot('"demo-output"');
2331

24-
expect(zip.getProject()).toMatchInlineSnapshot(`undefined`);
32+
expect(zip.getProject()).toMatchInlineSnapshot('undefined');
2533
zip.setProject(demoProject);
2634
expect(zip.getProject()).toBeTruthy();
2735

28-
expect(zip.getOutputPath()).toMatchInlineSnapshot(`"demo-output"`);
36+
expect(zip.getOutputPath()).toMatchInlineSnapshot('"demo-output"');
2937
expect(zip.setOutputPath('output')).toBe(undefined);
30-
expect(zip.getOutputPath()).toMatchInlineSnapshot(`"output"`);
38+
expect(zip.getOutputPath()).toMatchInlineSnapshot('"output"');
3139

3240
const publishRes = await zip.publish({
3341
project: demoProject,
@@ -41,4 +49,39 @@ describe('public/publisher/zip/zip', () => {
4149
const zip = CodeGen.publishers.zip({});
4250
expect(zip.publish()).rejects.toBeTruthy();
4351
});
52+
53+
it('should publish the project as a zip file in the browser', async () => {
54+
const zipContent = 'zip content';
55+
const zipName = 'example-project';
56+
jest.spyOn(utils, 'isNodeProcess').mockReturnValue(false);
57+
// new Zip 里面也有平台判断,所以这里 mock
58+
jest.spyOn(utils, 'generateProjectZip').mockResolvedValue(zipContent as any);
59+
const spy = jest.spyOn(fileSaver, 'saveAs');
60+
61+
const zip = CodeGen.publishers.zip({
62+
projectSlug: zipName,
63+
});
64+
65+
const demoProject = {
66+
name: 'demo',
67+
dirs: [],
68+
files: [
69+
{
70+
name: 'package',
71+
ext: 'json',
72+
content: '{ "name": "demo", "version": "1.0.0" }',
73+
},
74+
],
75+
};
76+
77+
zip.setProject(demoProject);
78+
const publishRes = await zip.publish({
79+
project: demoProject,
80+
});
81+
82+
expect(publishRes.success).toBeTruthy();
83+
expect(spy).toBeCalledWith(zipContent, `${zipName}.zip`);
84+
spy.mockReset();
85+
spy.mockRestore();
86+
});
4487
});

0 commit comments

Comments
 (0)