diff --git a/demo/74-nodejs-stream.ts b/demo/74-nodejs-stream.ts new file mode 100644 index 0000000000..4dea1f7524 --- /dev/null +++ b/demo/74-nodejs-stream.ts @@ -0,0 +1,31 @@ +// Simple example to add text to a document +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { Document, Packer, Paragraph, TextRun } from "../build"; + +const doc = new Document({ + sections: [ + { + properties: {}, + children: [ + new Paragraph({ + children: [ + new TextRun("Hello World"), + new TextRun({ + text: "Foo Bar", + bold: true, + }), + new TextRun({ + text: "\tGithub is the best", + bold: true, + }), + ], + }), + ], + }, + ], +}); + +Packer.toStream(doc).then((stream) => { + stream.pipe(fs.createWriteStream("My Document.docx")); +}); diff --git a/src/export/packer/packer.spec.ts b/src/export/packer/packer.spec.ts index b2c3e21836..f0ed3d8b94 100644 --- a/src/export/packer/packer.spec.ts +++ b/src/export/packer/packer.spec.ts @@ -122,4 +122,52 @@ describe("Packer", () => { (Packer as any).compiler.compile.restore(); }); }); + + describe("#toStream()", () => { + it("should create a standard docx file", async () => { + // tslint:disable-next-line: no-any + stub((Packer as any).compiler, "compile").callsFake(() => ({ + // tslint:disable-next-line: no-empty + generateNodeStream: () => ({ + on: (event: string, cb: () => void) => { + if (event === "end") { + cb(); + } + }, + }), + })); + const stream = await Packer.toStream(file); + return new Promise((resolve, reject) => { + stream.on("error", () => { + reject(); + }); + + stream.on("end", () => { + resolve(); + }); + }); + }); + + it("should handle exception if it throws any", async () => { + // tslint:disable-next-line:no-any + const compiler = stub((Packer as any).compiler, "compile").callsFake(() => ({ + // tslint:disable-next-line: no-empty + on: (event: string, cb: () => void) => { + if (event === "error") { + cb(); + } + }, + })); + + compiler.throwsException(); + return Packer.toStream(file).catch((error) => { + assert.isDefined(error); + }); + }); + + afterEach(() => { + // tslint:disable-next-line:no-any + (Packer as any).compiler.compile.restore(); + }); + }); }); diff --git a/src/export/packer/packer.ts b/src/export/packer/packer.ts index 4d047f7381..5d233ec0ef 100644 --- a/src/export/packer/packer.ts +++ b/src/export/packer/packer.ts @@ -1,4 +1,5 @@ import { File } from "@file/file"; +import { Stream } from "stream"; import { Compiler } from "./next-compiler"; @@ -57,5 +58,17 @@ export class Packer { return zipData; } + public static async toStream(file: File, prettify?: boolean | PrettifyType): Promise { + const zip = this.compiler.compile(file, prettify); + const zipData = zip.generateNodeStream({ + type: "nodebuffer", + streamFiles: true, + mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + compression: "DEFLATE", + }); + + return zipData; + } + private static readonly compiler = new Compiler(); } diff --git a/webpack.config.ts b/webpack.config.ts index 0f03537add..5871440f3f 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -23,6 +23,9 @@ const configuration = { stream: require.resolve("stream-browserify"), }, plugins: [new TsconfigPathsPlugin()], + alias: { + jszip: require.resolve('jszip/lib/index.js'), + }, }, module: {