Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: zip publisher support browser #2744

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions modules/code-generator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,16 +94,26 @@ await CodeGenerator.init();
4. 出码

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

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

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

5. 下载 zip 包

```js
// 写入到 zip 包
await CodeGenerator.publishers.zip().publish({
project, // 上一步生成的 project
projectSlug: 'your-project-slug', // 项目标识 -- 对应下载 your-project-slug.zip 文件
});
```

### 5)自定义出码

前端框架灵活多变,默认内置的出码方案很难满足所有人的需求,好在此代码生成器支持非常灵活的插件机制 -- 欢迎参考 ./src/plugins/xxx 来编写您自己的出码插件,然后参考 ./src/solutions/xxx 将各种插件组合成一套适合您的业务场景的出码方案。
Expand Down
2 changes: 2 additions & 0 deletions modules/code-generator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
"change-case": "^3.1.0",
"commander": "^6.1.0",
"debug": "^4.3.2",
"file-saver": "^2.0.5",
"fp-ts": "^2.11.9",
"fs-extra": "9.x",
"glob": "^7.2.0",
Expand Down Expand Up @@ -109,6 +110,7 @@
"devDependencies": {
"@iceworks/spec": "^1.4.2",
"@types/babel__traverse": "^7.11.0",
"@types/file-saver": "^2.0.7",
"@types/jest": "^27.0.2",
"@types/lodash": "^4.14.162",
"@types/node": "^14.14.20",
Expand Down
18 changes: 12 additions & 6 deletions modules/code-generator/src/publisher/zip/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { ResultDir } from '@alilc/lowcode-types';
import { PublisherFactory, IPublisher, IPublisherFactoryParams, PublisherError } from '../../types';
import { getErrorMessage } from '../../utils/errors';
import { isNodeProcess, writeZipToDisk, generateProjectZip } from './utils';
import { saveAs } from 'file-saver';

// export type ZipBuffer = Buffer | Blob;
export type ZipBuffer = Buffer;
export type ZipBuffer = Buffer | Blob;

declare type ZipPublisherResponse = string | ZipBuffer;

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

// If not output path is provided, zip is not written to disk
const projectOutputPath = options.outputPath || outputPath;
if (projectOutputPath && isNodeProcess()) {
await writeZipToDisk(projectOutputPath, zipContent, zipName);
if (isNodeProcess()) {
// If not output path is provided on the node side, zip is not written to disk
const projectOutputPath = options.outputPath || outputPath;
if (projectOutputPath) {
await writeZipToDisk(projectOutputPath, zipContent, zipName);
}
} else {
// the browser end does not require a path
// auto download zip files
saveAs(zipContent as Blob, `${zipName}.zip`);
}

return { success: true, payload: zipContent };
Expand Down
3 changes: 1 addition & 2 deletions modules/code-generator/src/publisher/zip/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ export const writeZipToDisk = (
export const generateProjectZip = async (project: ResultDir): Promise<ZipBuffer> => {
let zip = new JSZip();
zip = writeFolderToZip(project, zip, true);
// const zipType = isNodeProcess() ? 'nodebuffer' : 'blob';
const zipType = 'nodebuffer'; // 目前先只支持 node 调用
const zipType = isNodeProcess() ? 'nodebuffer' : 'blob';
return zip.generateAsync({ type: zipType });
};

Expand Down
51 changes: 47 additions & 4 deletions modules/code-generator/tests/public/publisher/zip/zip.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import CodeGen from '../../../../src';
import fileSaver from 'file-saver';
import * as utils from '../../../../src/publisher/zip/utils';

jest.mock('file-saver');

describe('public/publisher/zip/zip', () => {
afterEach(() => {
jest.clearAllMocks();
});

it('should works', async () => {
const zip = CodeGen.publishers.zip({
outputPath: 'demo-output',
Expand All @@ -19,15 +27,15 @@ describe('public/publisher/zip/zip', () => {
],
};

expect(zip.getOutputPath()).toMatchInlineSnapshot(`"demo-output"`);
expect(zip.getOutputPath()).toMatchInlineSnapshot('"demo-output"');

expect(zip.getProject()).toMatchInlineSnapshot(`undefined`);
expect(zip.getProject()).toMatchInlineSnapshot('undefined');
zip.setProject(demoProject);
expect(zip.getProject()).toBeTruthy();

expect(zip.getOutputPath()).toMatchInlineSnapshot(`"demo-output"`);
expect(zip.getOutputPath()).toMatchInlineSnapshot('"demo-output"');
expect(zip.setOutputPath('output')).toBe(undefined);
expect(zip.getOutputPath()).toMatchInlineSnapshot(`"output"`);
expect(zip.getOutputPath()).toMatchInlineSnapshot('"output"');

const publishRes = await zip.publish({
project: demoProject,
Expand All @@ -41,4 +49,39 @@ describe('public/publisher/zip/zip', () => {
const zip = CodeGen.publishers.zip({});
expect(zip.publish()).rejects.toBeTruthy();
});

it('should publish the project as a zip file in the browser', async () => {
const zipContent = 'zip content';
const zipName = 'example-project';
jest.spyOn(utils, 'isNodeProcess').mockReturnValue(false);
// new Zip 里面也有平台判断,所以这里 mock
jest.spyOn(utils, 'generateProjectZip').mockResolvedValue(zipContent as any);
const spy = jest.spyOn(fileSaver, 'saveAs');

const zip = CodeGen.publishers.zip({
projectSlug: zipName,
});

const demoProject = {
name: 'demo',
dirs: [],
files: [
{
name: 'package',
ext: 'json',
content: '{ "name": "demo", "version": "1.0.0" }',
},
],
};

zip.setProject(demoProject);
const publishRes = await zip.publish({
project: demoProject,
});

expect(publishRes.success).toBeTruthy();
expect(spy).toBeCalledWith(zipContent, `${zipName}.zip`);
spy.mockReset();
spy.mockRestore();
});
});
Loading