diff --git a/modules/code-generator/README.md b/modules/code-generator/README.md index 03ce94b54..1d67b3aa1 100644 --- a/modules/code-generator/README.md +++ b/modules/code-generator/README.md @@ -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 将各种插件组合成一套适合您的业务场景的出码方案。 diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index 6ff1ecb63..5c0d91cc0 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -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", @@ -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", diff --git a/modules/code-generator/src/publisher/zip/index.ts b/modules/code-generator/src/publisher/zip/index.ts index cc2f082b2..0ac0b6f67 100644 --- a/modules/code-generator/src/publisher/zip/index.ts +++ b/modules/code-generator/src/publisher/zip/index.ts @@ -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; @@ -44,10 +44,16 @@ export const createZipPublisher: PublisherFactory => { 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 }); }; diff --git a/modules/code-generator/tests/public/publisher/zip/zip.test.ts b/modules/code-generator/tests/public/publisher/zip/zip.test.ts index ed37980d0..d51957004 100644 --- a/modules/code-generator/tests/public/publisher/zip/zip.test.ts +++ b/modules/code-generator/tests/public/publisher/zip/zip.test.ts @@ -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', @@ -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, @@ -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(); + }); });