Convert to vite and clean up build

This commit is contained in:
Dolan Miu
2023-06-01 02:05:35 +01:00
parent 352cde743f
commit 0cbb5fb0a3
20 changed files with 2859 additions and 473 deletions

View File

@ -23,6 +23,7 @@
"dolan", "dolan",
"execa", "execa",
"falsey", "falsey",
"fflate",
"Initializable", "Initializable",
"iroha", "iroha",
"jsonify", "jsonify",

View File

@ -5,7 +5,9 @@ env:
node: true node: true
parser: "@typescript-eslint/parser" parser: "@typescript-eslint/parser"
parserOptions: parserOptions:
project: tsconfig.json project:
- tsconfig.json
- demo/tsconfig.json
sourceType: module sourceType: module
plugins: plugins:
- eslint-plugin-import - eslint-plugin-import
@ -226,6 +228,8 @@ rules:
no-unused-vars: no-unused-vars:
- error - error
- argsIgnorePattern: ^[_]+$ - argsIgnorePattern: ^[_]+$
ignorePatterns:
- vite.config.ts
overrides: overrides:
- files: - files:
- "*.spec.ts" - "*.spec.ts"

View File

@ -16,10 +16,6 @@ updates:
- 14.14.29 - 14.14.29
- 14.14.30 - 14.14.30
- 15.0.0 - 15.0.0
- dependency-name: webpack
versions:
- 5.31.2
- 5.35.0
- dependency-name: ts-loader - dependency-name: ts-loader
versions: versions:
- 9.1.0 - 9.1.0

View File

@ -1,7 +1,7 @@
// Simple example to add text to a document // Simple example to add text to a document
// Import from 'docx' rather than '../build' if you install from npm // Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs"; import * as fs from "fs";
import { Document, Packer, Paragraph, Tab, TextRun } from "../build"; import { Document, Packer, Paragraph, Tab, TextRun } from "docx";
const doc = new Document({ const doc = new Document({
sections: [ sections: [

View File

@ -1,17 +1,7 @@
// Example on how to customize the look at feel using Styles // Example on how to customize the look at feel using Styles
// Import from 'docx' rather than '../build' if you install from npm // Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs"; import * as fs from "fs";
import { import { AlignmentType, convertInchesToTwip, Document, HeadingLevel, LevelFormat, Packer, Paragraph, TextRun, UnderlineType } from "docx";
AlignmentType,
convertInchesToTwip,
Document,
HeadingLevel,
LevelFormat,
Packer,
Paragraph,
TextRun,
UnderlineType,
} from "../build";
const doc = new Document({ const doc = new Document({
creator: "Clippy", creator: "Clippy",

View File

@ -11,7 +11,7 @@ import {
Tab, Tab,
TextRun, TextRun,
VerticalPositionAlign, VerticalPositionAlign,
} from "../build"; } from "docx";
const doc = new Document({ const doc = new Document({
sections: [ sections: [

View File

@ -1,7 +1,7 @@
// Exporting the document as a stream // Exporting the document as a stream
// Import from 'docx' rather than '../build' if you install from npm // Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs"; import * as fs from "fs";
import { Document, Packer, Paragraph, Tab, TextRun } from "../build"; import { Document, Packer, Paragraph, Tab, TextRun } from "docx";
const doc = new Document({ const doc = new Document({
sections: [ sections: [

View File

@ -1,21 +1,21 @@
// Example of using tab stops // Example of using tab stops
// Import from 'docx' rather than '../build' if you install from npm // Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs"; import * as fs from "fs";
import { Document, HeadingLevel, Packer, Paragraph, TabStopPosition, TabStopType, TextRun } from "../build"; import { Document, HeadingLevel, Packer, Paragraph, TabStopPosition, TabStopType, TextRun } from "docx";
const columnWidth = TabStopPosition.MAX / 4; const columnWidth = TabStopPosition.MAX / 4;
const receiptTabStops = [ const receiptTabStops = [
// no need to define first left tab column // no need to define first left tab column
// the right aligned tab column position should point to the end of column // the right aligned tab column position should point to the end of column
// i.e. in this case // i.e. in this case
// (end position of 1st) + (end position of current) // (end position of 1st) + (end position of current)
// columnWidth + columnWidth = columnWidth * 2 // columnWidth + columnWidth = columnWidth * 2
{ type: TabStopType.RIGHT, position: columnWidth * 2 }, { type: TabStopType.RIGHT, position: columnWidth * 2 },
{ type: TabStopType.RIGHT, position: columnWidth * 3 }, { type: TabStopType.RIGHT, position: columnWidth * 3 },
{ type: TabStopType.RIGHT, position: TabStopPosition.MAX }, { type: TabStopType.RIGHT, position: TabStopPosition.MAX },
], ];
twoTabStops = [{ type: TabStopType.RIGHT, position: TabStopPosition.MAX }]; const twoTabStops = [{ type: TabStopType.RIGHT, position: TabStopPosition.MAX }];
const doc = new Document({ const doc = new Document({
sections: [ sections: [

View File

@ -1,14 +1,13 @@
// tslint:disable:no-console /* eslint-disable no-console */
import fs from "fs"; import fs from "fs";
import prompt from "prompt"; import prompt, { Schema } from "prompt";
// import shelljs from "shelljs";
import { $ } from "execa"; import { $ } from "execa";
console.log("What demo do you wish to run? (Enter a number)"); console.log("What demo do you wish to run? (Enter a number)");
const schema = { const schema: Schema = {
properties: { properties: {
number: { demoNumber: {
pattern: /^[0-9]+$/, pattern: /^[0-9]+$/,
message: "Please enter a number.", message: "Please enter a number.",
required: true, required: true,
@ -18,8 +17,8 @@ const schema = {
prompt.start(); prompt.start();
prompt.get(schema as any, async (_, result) => { prompt.get(schema, async (_, result) => {
const demoNumber = result.number as string; const demoNumber = result.demoNumber as string;
const files = fs.readdirSync("./demo").filter((fn) => fn.startsWith(demoNumber)); const files = fs.readdirSync("./demo").filter((fn) => fn.startsWith(demoNumber));
if (files.length === 0) { if (files.length === 0) {
@ -30,12 +29,6 @@ prompt.get(schema as any, async (_, result) => {
const filePath = `./demo/${files[0]}`; const filePath = `./demo/${files[0]}`;
console.log(`Running demo ${demoNumber}: ${files[0]}`); console.log(`Running demo ${demoNumber}: ${files[0]}`);
const { stdout } = await $`npm run ts-node -- ${filePath}`; await $`ts-node --project demo/tsconfig.json ${filePath}`;
console.log(stdout); console.log("Successfully created document!");
// if (shelljs.exec(`npm run ts-node -- ${filePath}`).code === 0) {
// console.log("Document created successfully");
// } else {
// console.error("Something went wrong with the demo");
// }
}); });

10
demo/tsconfig.json Normal file
View File

@ -0,0 +1,10 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"rootDir": "./",
"paths": {
"docx": ["../build"]
}
},
"include": ["../demo"]
}

2658
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,20 +2,33 @@
"name": "docx", "name": "docx",
"version": "8.0.3", "version": "8.0.3",
"description": "Easily generate .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.", "description": "Easily generate .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.",
"main": "build/index.js",
"type": "module", "type": "module",
"main": "build/index.umd.cjs",
"module": "./build/index.js",
"types": "./build/index.d.ts",
"exports": {
".": {
"browser": {
"default": "./build/index.umd.cjs"
},
"require": "./build/index.cjs",
"types": "./build/index.d.ts",
"import": "./build/index.js",
"default": "./build/index.js"
}
},
"files": [
"build"
],
"scripts": { "scripts": {
"dev": "vite",
"build": "tsc && vite build", "build": "tsc && vite build",
"preview": "vite preview",
"pretest": "rimraf ./build", "pretest": "rimraf ./build",
"test": "mocha --config=.mocharc.json", "test": "mocha --config=.mocharc.json",
"test.coverage": "nyc npm test", "test.coverage": "nyc npm test",
"test.watch": "npm test -- --watch", "test.watch": "npm test -- --watch",
"prepublishOnly": "npm run build --production", "prepublishOnly": "npm run build --omit=dev",
"lint": "eslint --ext .ts src", "lint": "eslint --ext .ts src",
"webpack": "rimraf ./build && webpack --config ./webpack.config.ts", "demo": "ts-node --project demo/tsconfig.json ./demo/index.ts",
"demo": "ts-node --esm ./demo/index.ts",
"typedoc": "rimraf ./build && typedoc src/index.ts --tsconfig tsconfig.typedoc.json", "typedoc": "rimraf ./build && typedoc src/index.ts --tsconfig tsconfig.typedoc.json",
"style": "prettier -l \"{src,scripts,demo}/**/*.{ts,html}\"", "style": "prettier -l \"{src,scripts,demo}/**/*.{ts,html}\"",
"style.fix": "npm run style -- --write", "style.fix": "npm run style -- --write",
@ -24,15 +37,12 @@
"e2e": "ts-node scripts/e2e.ts", "e2e": "ts-node scripts/e2e.ts",
"serve.docs": "cd docs && docsify serve", "serve.docs": "cd docs && docsify serve",
"extract": "ts-node --project tsconfig.spec.json scripts/extract-document.ts", "extract": "ts-node --project tsconfig.spec.json scripts/extract-document.ts",
"ts-node": "ts-node --skip-project" "ts-node": "ts-node --project demo/tsconfig.json"
}, },
"pre-commit": [ "pre-commit": [
"style", "style",
"lint" "lint"
], ],
"files": [
"build"
],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/dolanmiu/docx.git" "url": "git+https://github.com/dolanmiu/docx.git"
@ -49,10 +59,10 @@
"officegen", "officegen",
"clippy" "clippy"
], ],
"types": "./build/index.d.ts",
"dependencies": { "dependencies": {
"@types/node": "^18.0.0", "@types/node": "^18.0.0",
"jszip": "^3.1.5", "fflate": "^0.8.0",
"jszip": "3.2.0",
"nanoid": "^3.3.4", "nanoid": "^3.3.4",
"xml": "^1.0.1", "xml": "^1.0.1",
"xml-js": "^1.6.8" "xml-js": "^1.6.8"
@ -101,7 +111,6 @@
"request": "^2.88.0", "request": "^2.88.0",
"request-promise": "^4.2.2", "request-promise": "^4.2.2",
"rimraf": "^4.0.4", "rimraf": "^4.0.4",
"shelljs": "^0.8.4",
"sinon": "^15.0.0", "sinon": "^15.0.0",
"stream-browserify": "^3.0.0", "stream-browserify": "^3.0.0",
"ts-loader": "^9.0.0", "ts-loader": "^9.0.0",
@ -112,6 +121,8 @@
"typescript": "5.0.3", "typescript": "5.0.3",
"unzipper": "^0.10.11", "unzipper": "^0.10.11",
"vite": "^4.3.2", "vite": "^4.3.2",
"vite-plugin-dts": "^2.3.0",
"vite-plugin-node-polyfills": "^0.8.2",
"vite-tsconfig-paths": "^4.2.0", "vite-tsconfig-paths": "^4.2.0",
"webpack": "^5.28.0", "webpack": "^5.28.0",
"webpack-cli": "^5.0.0" "webpack-cli": "^5.0.0"

View File

@ -1,180 +1,180 @@
/* tslint:disable:typedef space-before-function-paren */ // /* tslint:disable:typedef space-before-function-paren */
import { expect } from "chai"; // import { expect } from "chai";
import * as sinon from "sinon"; // import * as sinon from "sinon";
import { File } from "@file/file"; // import { File } from "@file/file";
import { Footer, Header } from "@file/header"; // import { Footer, Header } from "@file/header";
import { ImageRun, Paragraph } from "@file/paragraph"; // import { ImageRun, Paragraph } from "@file/paragraph";
import * as convenienceFunctions from "@util/convenience-functions"; // import * as convenienceFunctions from "@util/convenience-functions";
import { Compiler } from "./next-compiler"; // import { Compiler } from "./next-compiler";
describe("Compiler", () => { // describe("Compiler", () => {
let compiler: Compiler; // let compiler: Compiler;
beforeEach(() => { // beforeEach(() => {
compiler = new Compiler(); // compiler = new Compiler();
}); // });
before(() => { // before(() => {
sinon.stub(convenienceFunctions, "uniqueId").callsFake(() => "test"); // sinon.stub(convenienceFunctions, "uniqueId").callsFake(() => "test");
}); // });
after(() => { // after(() => {
(convenienceFunctions.uniqueId as sinon.SinonStub).restore(); // (convenienceFunctions.uniqueId as sinon.SinonStub).restore();
}); // });
describe("#compile()", () => { // describe("#compile()", () => {
it("should pack all the content", function () { // it("should pack all the content", async function () {
this.timeout(99999999); // this.timeout(99999999);
const file = new File({ // const file = new File({
sections: [], // sections: [],
comments: { // comments: {
children: [], // children: [],
}, // },
}); // });
const zipFile = compiler.compile(file); // const zipFile = await compiler.compile(file);
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name); // const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
expect(fileNames).is.an.instanceof(Array); // expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(17); // expect(fileNames).has.length(17);
expect(fileNames).to.include("word/document.xml"); // expect(fileNames).to.include("word/document.xml");
expect(fileNames).to.include("word/styles.xml"); // expect(fileNames).to.include("word/styles.xml");
expect(fileNames).to.include("docProps/core.xml"); // expect(fileNames).to.include("docProps/core.xml");
expect(fileNames).to.include("docProps/custom.xml"); // expect(fileNames).to.include("docProps/custom.xml");
expect(fileNames).to.include("docProps/app.xml"); // expect(fileNames).to.include("docProps/app.xml");
expect(fileNames).to.include("word/numbering.xml"); // expect(fileNames).to.include("word/numbering.xml");
expect(fileNames).to.include("word/footnotes.xml"); // expect(fileNames).to.include("word/footnotes.xml");
expect(fileNames).to.include("word/_rels/footnotes.xml.rels"); // expect(fileNames).to.include("word/_rels/footnotes.xml.rels");
expect(fileNames).to.include("word/settings.xml"); // expect(fileNames).to.include("word/settings.xml");
expect(fileNames).to.include("word/comments.xml"); // expect(fileNames).to.include("word/comments.xml");
expect(fileNames).to.include("word/_rels/document.xml.rels"); // expect(fileNames).to.include("word/_rels/document.xml.rels");
expect(fileNames).to.include("[Content_Types].xml"); // expect(fileNames).to.include("[Content_Types].xml");
expect(fileNames).to.include("_rels/.rels"); // expect(fileNames).to.include("_rels/.rels");
}); // });
it("should pack all additional headers and footers", function () { // it("should pack all additional headers and footers", function () {
const file = new File({ // const file = new File({
sections: [ // sections: [
{ // {
headers: { // headers: {
default: new Header({ // default: new Header({
children: [new Paragraph("test")], // children: [new Paragraph("test")],
}), // }),
}, // },
footers: { // footers: {
default: new Footer({ // default: new Footer({
children: [new Paragraph("test")], // children: [new Paragraph("test")],
}), // }),
}, // },
children: [], // children: [],
}, // },
{ // {
headers: { // headers: {
default: new Header({ // default: new Header({
children: [new Paragraph("test")], // children: [new Paragraph("test")],
}), // }),
}, // },
footers: { // footers: {
default: new Footer({ // default: new Footer({
children: [new Paragraph("test")], // children: [new Paragraph("test")],
}), // }),
}, // },
children: [], // children: [],
}, // },
], // ],
}); // });
this.timeout(99999999); // this.timeout(99999999);
const zipFile = compiler.compile(file); // const zipFile = compiler.compile(file);
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name); // const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
expect(fileNames).is.an.instanceof(Array); // expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(25); // expect(fileNames).has.length(25);
expect(fileNames).to.include("word/header1.xml"); // expect(fileNames).to.include("word/header1.xml");
expect(fileNames).to.include("word/_rels/header1.xml.rels"); // expect(fileNames).to.include("word/_rels/header1.xml.rels");
expect(fileNames).to.include("word/header2.xml"); // expect(fileNames).to.include("word/header2.xml");
expect(fileNames).to.include("word/_rels/header2.xml.rels"); // expect(fileNames).to.include("word/_rels/header2.xml.rels");
expect(fileNames).to.include("word/footer1.xml"); // expect(fileNames).to.include("word/footer1.xml");
expect(fileNames).to.include("word/_rels/footer1.xml.rels"); // expect(fileNames).to.include("word/_rels/footer1.xml.rels");
expect(fileNames).to.include("word/footer2.xml"); // expect(fileNames).to.include("word/footer2.xml");
expect(fileNames).to.include("word/_rels/footer2.xml.rels"); // expect(fileNames).to.include("word/_rels/footer2.xml.rels");
}); // });
it("should call the format method X times equalling X files to be formatted", () => { // it("should call the format method X times equalling X files to be formatted", () => {
// This test is required because before, there was a case where Document was formatted twice, which was inefficient // // This test is required because before, there was a case where Document was formatted twice, which was inefficient
// This also caused issues such as running prepForXml multiple times as format() was ran multiple times. // // This also caused issues such as running prepForXml multiple times as format() was ran multiple times.
const paragraph = new Paragraph(""); // const paragraph = new Paragraph("");
const file = new File({ // const file = new File({
sections: [ // sections: [
{ // {
properties: {}, // properties: {},
children: [paragraph], // children: [paragraph],
}, // },
], // ],
}); // });
// tslint:disable-next-line: no-string-literal // // tslint:disable-next-line: no-string-literal
const spy = sinon.spy(compiler["formatter"], "format"); // const spy = sinon.spy(compiler["formatter"], "format");
compiler.compile(file); // compiler.compile(file);
expect(spy.callCount).to.equal(13); // expect(spy.callCount).to.equal(13);
}); // });
it("should work with media datas", () => { // it("should work with media datas", () => {
// This test is required because before, there was a case where Document was formatted twice, which was inefficient // // This test is required because before, there was a case where Document was formatted twice, which was inefficient
// This also caused issues such as running prepForXml multiple times as format() was ran multiple times. // // This also caused issues such as running prepForXml multiple times as format() was ran multiple times.
const file = new File({ // const file = new File({
sections: [ // sections: [
{ // {
headers: { // headers: {
default: new Header({ // default: new Header({
children: [new Paragraph("test")], // children: [new Paragraph("test")],
}), // }),
}, // },
footers: { // footers: {
default: new Footer({ // default: new Footer({
children: [new Paragraph("test")], // children: [new Paragraph("test")],
}), // }),
}, // },
children: [ // children: [
new Paragraph({ // new Paragraph({
children: [ // children: [
new ImageRun({ // new ImageRun({
data: Buffer.from("", "base64"), // data: Buffer.from("", "base64"),
transformation: { // transformation: {
width: 100, // width: 100,
height: 100, // height: 100,
}, // },
}), // }),
], // ],
}), // }),
], // ],
}, // },
], // ],
}); // });
// tslint:disable-next-line: no-string-literal // // tslint:disable-next-line: no-string-literal
sinon.stub(compiler["imageReplacer"], "getMediaData").returns([ // sinon.stub(compiler["imageReplacer"], "getMediaData").returns([
{ // {
stream: Buffer.from(""), // stream: Buffer.from(""),
fileName: "test", // fileName: "test",
transformation: { // transformation: {
pixels: { // pixels: {
x: 100, // x: 100,
y: 100, // y: 100,
}, // },
emus: { // emus: {
x: 100, // x: 100,
y: 100, // y: 100,
}, // },
}, // },
}, // },
]); // ]);
compiler.compile(file); // compiler.compile(file);
}); // });
}); // });
}); // });

View File

@ -1,4 +1,4 @@
import JSZip from "jszip"; import { strToU8, zip } from "fflate";
import xml from "xml"; import xml from "xml";
import { File } from "@file/file"; import { File } from "@file/file";
@ -44,26 +44,39 @@ export class Compiler {
this.numberingReplacer = new NumberingReplacer(); this.numberingReplacer = new NumberingReplacer();
} }
public compile(file: File, prettifyXml?: PrettifyType): JSZip { public compile(file: File, prettifyXml?: PrettifyType): Promise<Uint8Array> {
const zip = new JSZip();
const xmlifiedFileMapping = this.xmlifyFile(file, prettifyXml); const xmlifiedFileMapping = this.xmlifyFile(file, prettifyXml);
const map = new Map<string, IXmlifyedFile | readonly IXmlifyedFile[]>(Object.entries(xmlifiedFileMapping)); const map = new Map<string, IXmlifyedFile | readonly IXmlifyedFile[]>(Object.entries(xmlifiedFileMapping));
for (const [, obj] of map) { return new Promise<Uint8Array>((resolve, reject) => {
if (Array.isArray(obj)) { zip(
for (const subFile of obj as readonly IXmlifyedFile[]) { {
zip.file(subFile.path, subFile.data); ...Array.from(map.entries()).reduce((acc, [, obj]) => {
} if (Array.isArray(obj)) {
} else { for (const subFile of obj as readonly IXmlifyedFile[]) {
zip.file((obj as IXmlifyedFile).path, (obj as IXmlifyedFile).data); // eslint-disable-next-line functional/immutable-data
} acc[subFile.path] = strToU8(subFile.data);
} }
} else {
// eslint-disable-next-line functional/immutable-data
acc[(obj as IXmlifyedFile).path] = strToU8((obj as IXmlifyedFile).data);
}
for (const { stream, fileName } of file.Media.Array) { return acc;
zip.file(`word/media/${fileName}`, stream); // eslint-disable-next-line @typescript-eslint/no-explicit-any
} }, {} as any),
...file.Media.Array.reduce((acc, { stream, fileName }) => ({ ...acc, [`word/media/${fileName}`]: stream }), {}),
return zip; },
{},
(err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
},
);
});
} }
private xmlifyFile(file: File, prettify?: PrettifyType): IXmlifyedFileMapping { private xmlifyFile(file: File, prettify?: PrettifyType): IXmlifyedFileMapping {

View File

@ -1,5 +1,6 @@
import { Stream } from "stream"; import { Stream } from "stream";
import { File } from "@file/file"; import { File } from "@file/file";
import { strFromU8 } from "fflate";
import { Compiler } from "./next-compiler"; import { Compiler } from "./next-compiler";
@ -15,59 +16,52 @@ export enum PrettifyType {
export class Packer { export class Packer {
public static async toString(file: File, prettify?: boolean | PrettifyType): Promise<string> { public static async toString(file: File, prettify?: boolean | PrettifyType): Promise<string> {
const zip = this.compiler.compile(file, prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify); const zip = await this.compiler.compile(
const zipData = await zip.generateAsync({ file,
type: "string", prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify,
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", );
compression: "DEFLATE", return strFromU8(zip);
});
return zipData;
} }
public static async toBuffer(file: File, prettify?: boolean | PrettifyType): Promise<Buffer> { public static async toBuffer(file: File, prettify?: boolean | PrettifyType): Promise<Buffer> {
const zip = this.compiler.compile(file, prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify); const zip = await this.compiler.compile(
const zipData = await zip.generateAsync({ file,
type: "nodebuffer", prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify,
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", );
compression: "DEFLATE", return Buffer.from(zip.buffer);
});
return zipData;
} }
public static async toBase64String(file: File, prettify?: boolean | PrettifyType): Promise<string> { public static async toBase64String(file: File, prettify?: boolean | PrettifyType): Promise<string> {
const zip = this.compiler.compile(file, prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify); const zip = await this.compiler.compile(
const zipData = await zip.generateAsync({ file,
type: "base64", prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify,
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", );
compression: "DEFLATE",
});
return zipData; return Promise.resolve(strFromU8(zip));
} }
public static async toBlob(file: File, prettify?: boolean | PrettifyType): Promise<Blob> { public static async toBlob(file: File, prettify?: boolean | PrettifyType): Promise<Blob> {
const zip = this.compiler.compile(file, prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify); const zip = await this.compiler.compile(
const zipData = await zip.generateAsync({ file,
type: "blob", prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify,
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", );
compression: "DEFLATE",
});
return zipData; return new Blob([zip.buffer]);
} }
public static toStream(file: File, prettify?: boolean | PrettifyType): Stream { public static toStream(file: File, prettify?: boolean | PrettifyType): Stream {
const zip = this.compiler.compile(file, prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify); const zip = this.compiler.compile(file, prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify);
const zipData = zip.generateNodeStream({
type: "nodebuffer",
streamFiles: true,
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
compression: "DEFLATE",
});
return zipData; const stream = new Stream();
// eslint-disable-next-line functional/immutable-data
stream.pipe = (dest) => {
zip.then((z) => {
dest.write(z);
});
return dest;
};
return stream;
} }
private static readonly compiler = new Compiler(); private static readonly compiler = new Compiler();

View File

@ -1,5 +0,0 @@
{
"extends": "./tsconfig.json",
"include": ["src/**/*.ts"],
"exclude": ["src/**/*.spec.ts"]
}

View File

@ -36,6 +36,7 @@
} }
}, },
"ts-node": { "ts-node": {
"esm": true,
"compilerOptions": { "compilerOptions": {
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "node",

View File

@ -1,23 +0,0 @@
import { defineConfig } from "vite";
import { resolve } from "path";
import tsconfigPaths from "vite-tsconfig-paths";
/** @type {import('vite').UserConfig} */
export default defineConfig({
plugins: [
tsconfigPaths(),
],
build: {
lib: {
entry: [resolve(__dirname, "src/index.ts")],
name: "docx",
fileName: "index",
formats: ["iife", "es", "cjs", "umd"],
},
outDir: resolve(__dirname, "dist"),
commonjsOptions: {
include: [/node_modules/],
},
},
});

36
vite.config.ts Normal file
View File

@ -0,0 +1,36 @@
import { defineConfig } from "vite";
import { resolve } from "path";
import tsconfigPaths from "vite-tsconfig-paths";
import dts from "vite-plugin-dts";
import { nodePolyfills } from "vite-plugin-node-polyfills";
export default defineConfig({
plugins: [
tsconfigPaths(),
dts(),
nodePolyfills({
exclude: ["fs"],
protocolImports: true,
}),
],
resolve: {
alias: {
"@util/": `${resolve(__dirname, "src/util")}/`,
"@export/": `${resolve(__dirname, "src/export")}/`,
"@file/": `${resolve(__dirname, "src/file")}/`,
"@shared": `${resolve(__dirname, "src/shared")}`,
},
},
build: {
lib: {
entry: [resolve(__dirname, "src/index.ts")],
name: "docx",
fileName: "index",
formats: ["iife", "es", "cjs", "umd"],
},
outDir: resolve(__dirname, "build"),
commonjsOptions: {
include: [/node_modules/],
},
},
});

View File

@ -1,51 +0,0 @@
const path = require("path");
const { ProvidePlugin } = require("webpack");
const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
const configuration = {
mode: "production",
entry: "./src/index.ts",
output: {
path: path.resolve("build"),
filename: "index.js",
libraryTarget: "umd",
library: "docx",
globalObject: "globalThis",
},
resolve: {
extensions: [".ts", ".js"],
modules: [path.resolve("./src"), "node_modules"],
fallback: {
buffer: require.resolve("buffer"),
stream: require.resolve("stream-browserify"),
},
plugins: [new TsconfigPathsPlugin()],
alias: {
jszip: require.resolve('jszip/lib/index.js'),
},
},
module: {
rules: [
{
test: /\.ts$/,
loader: "ts-loader",
options: {
configFile: "tsconfig.lib.json",
},
},
],
},
plugins: [
// fix "process is not defined" error
new ProvidePlugin({
process: "process/browser",
}),
],
};
module.exports = configuration;