diff --git a/README.md b/README.md index a93a9911e..888df923f 100644 --- a/README.md +++ b/README.md @@ -122,13 +122,33 @@ doc.save("a4.pdf"); ### Optional dependencies Some functions of jsPDF require optional dependencies. E.g. the `html` method, which depends on `html2canvas` and, -when supplied with a string HTML document, `dompurify`. You need to install them explicitly, e.g.: +when supplied with a string HTML document, `dompurify`. JsPDF loads them dynamically when required +(using the respective module format, e.g. dynamic imports). Build tools like Webpack will automatically create separate +chunks for each of the optional dependencies. If your application does not use any of the optional dependencies, you +can prevent Webpack from generating the chunks by defining them as external dependencies: -```sh -npm install --save html2canvas dompurify +```js +// webpack.config.js +module.exports = { + // ... + externals: { + // only define the dependencies you are NOT using as externals! + canvg: "canvg", + html2canvas: "html2canvas", + dompurify: "dompurify" + } +}; ``` -jsPDF will then dynamically load them when required (using the respective module format, e.g. dynamic imports). +In **Vue CLI** projects, externals can be defined via the [configureWebpack](https://cli.vuejs.org/config/#configurewebpack) +or [chainWebpack](https://cli.vuejs.org/config/#chainwebpack) properties of the `vue.config.js` file +(needs to be created, first, in fresh projects). + +In **Angular** projects, externals can be defined using +[custom webpack builders](https://github.com/just-jeb/angular-builders/tree/master/packages/custom-webpack). + +In **React** (`create-react-app`) projects, externals can be defined by either using +[react-app-rewired](https://github.com/timarney/react-app-rewired) or ejecting. ### TypeScript/Angular/Webpack/React/etc. Configuration: diff --git a/package.json b/package.json index 0032d4d51..05b1d8f84 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,6 @@ "description": "PDF Document creation from JavaScript", "main": "dist/jspdf.node.min.js", "module": "dist/jspdf.es.min.js", - "browser": "dist/jspdf.umd.min.js", "files": [ "dist", "types/index.d.ts", diff --git a/rollup.config.js b/rollup.config.js index bd11e74cf..b18f872e8 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -38,10 +38,8 @@ const umdExternals = matchSubmodules([ ]); const externals = matchSubmodules([ ...Object.keys(pkg.dependencies || {}), - ...[ - ...Object.keys(pkg.peerDependencies || {}), - ...Object.keys(pkg.optionalDependencies || {}) - ] + ...Object.keys(pkg.peerDependencies || {}), + ...Object.keys(pkg.optionalDependencies || {}) ]); const umd = { @@ -162,7 +160,7 @@ const esPolyfills = { }; function matchSubmodules(externals) { - return externals.map(e => new RegExp(`^${e}[/\\\\]`)); + return externals.map(e => new RegExp(`^${e}(?:[/\\\\]|$)`)); } export default [umd, es, node, umdPolyfills, esPolyfills]; diff --git a/src/libs/loadOptionalLibrary.js b/src/libs/loadOptionalLibrary.js deleted file mode 100644 index 81fcdad03..000000000 --- a/src/libs/loadOptionalLibrary.js +++ /dev/null @@ -1,44 +0,0 @@ -/* eslint-disable no-unreachable */ -import { globalObject } from "./globalObject.js"; - -export function loadOptionalLibrary(name, globalName) { - globalName = globalName || name; - if (globalObject[globalName]) { - return Promise.resolve(globalObject[globalName]); - } - // @if MODULE_FORMAT='cjs' - return new Promise(function(resolve, reject) { - try { - resolve(require(name)); - } catch (e) { - reject(e); - } - }); - // @endif - - // @if MODULE_FORMAT='es' - return import(name); - // @endif - - // @if MODULE_FORMAT='umd' - if (typeof exports === "object" && typeof module !== "undefined") { - return new Promise(function(resolve, reject) { - try { - resolve(require(name)); - } catch (e) { - reject(e); - } - }); - } - if (typeof define === "function" && define.amd) { - return new Promise(function(resolve, reject) { - try { - require([name], resolve); - } catch (e) { - reject(e); - } - }); - } - return Promise.reject(new Error("Could not load " + name)); - // @endif -} diff --git a/src/modules/html.js b/src/modules/html.js index 294ff5486..13be0f7d4 100644 --- a/src/modules/html.js +++ b/src/modules/html.js @@ -8,7 +8,7 @@ */ import { jsPDF } from "../jspdf.js"; -import { loadOptionalLibrary } from "../libs/loadOptionalLibrary.js"; +import { globalObject } from "../libs/globalObject.js"; /** * jsPDF html PlugIn @@ -20,15 +20,83 @@ import { loadOptionalLibrary } from "../libs/loadOptionalLibrary.js"; "use strict"; function loadHtml2Canvas() { - return loadOptionalLibrary("html2canvas").catch(function(e) { - return Promise.reject(new Error("Could not load html2canvas: " + e)); - }); + return (function() { + if (globalObject["html2canvas"]) { + return Promise.resolve(globalObject["html2canvas"]); + } + + // @if MODULE_FORMAT='es' + return import("html2canvas"); + // @endif + + // @if MODULE_FORMAT!='es' + if (typeof exports === "object" && typeof module !== "undefined") { + return new Promise(function(resolve, reject) { + try { + resolve(require("html2canvas")); + } catch (e) { + reject(e); + } + }); + } + if (typeof define === "function" && define.amd) { + return new Promise(function(resolve, reject) { + try { + require(["html2canvas"], resolve); + } catch (e) { + reject(e); + } + }); + } + return Promise.reject(new Error("Could not load " + name)); + // @endif + })() + .catch(function(e) { + return Promise.reject(new Error("Could not load dompurify: " + e)); + }) + .then(function(html2canvas) { + return html2canvas.default ? html2canvas.default : html2canvas; + }); } function loadDomPurify() { - return loadOptionalLibrary("dompurify", "DOMPurify").catch(function(e) { - return Promise.reject(new Error("Could not load dompurify: " + e)); - }); + return (function() { + if (globalObject["DOMPurify"]) { + return Promise.resolve(globalObject["DOMPurify"]); + } + + // @if MODULE_FORMAT='es' + return import("dompurify"); + // @endif + + // @if MODULE_FORMAT!='es' + if (typeof exports === "object" && typeof module !== "undefined") { + return new Promise(function(resolve, reject) { + try { + resolve(require("dompurify")); + } catch (e) { + reject(e); + } + }); + } + if (typeof define === "function" && define.amd) { + return new Promise(function(resolve, reject) { + try { + require(["dompurify"], resolve); + } catch (e) { + reject(e); + } + }); + } + return Promise.reject(new Error("Could not load " + name)); + // @endif + })() + .catch(function(e) { + return Promise.reject(new Error("Could not load dompurify: " + e)); + }) + .then(function(dompurify) { + return dompurify.default ? dompurify.default : dompurify; + }); } /** diff --git a/src/modules/svg.js b/src/modules/svg.js index 34a57672b..cbd6a64eb 100644 --- a/src/modules/svg.js +++ b/src/modules/svg.js @@ -23,8 +23,8 @@ */ import { jsPDF } from "../jspdf.js"; -import { loadOptionalLibrary } from "../libs/loadOptionalLibrary.js"; import { console } from "../libs/console.js"; +import { globalObject } from "../libs/globalObject.js"; /** * jsPDF SVG plugin @@ -35,6 +35,46 @@ import { console } from "../libs/console.js"; (function(jsPDFAPI) { "use strict"; + function loadCanvg() { + return (function() { + if (globalObject["canvg"]) { + return Promise.resolve(globalObject["canvg"]); + } + + // @if MODULE_FORMAT='es' + return import("canvg"); + // @endif + + // @if MODULE_FORMAT!='es' + if (typeof exports === "object" && typeof module !== "undefined") { + return new Promise(function(resolve, reject) { + try { + resolve(require("canvg")); + } catch (e) { + reject(e); + } + }); + } + if (typeof define === "function" && define.amd) { + return new Promise(function(resolve, reject) { + try { + require(["canvg"], resolve); + } catch (e) { + reject(e); + } + }); + } + return Promise.reject(new Error("Could not load " + name)); + // @endif + })() + .catch(function(e) { + return Promise.reject(new Error("Could not load dompurify: " + e)); + }) + .then(function(canvg) { + return canvg.default ? canvg.default : canvg; + }); + } + /** * Parses SVG XML and saves it as image into the PDF. * @@ -89,7 +129,7 @@ import { console } from "../libs/console.js"; ignoreDimensions: true }; var doc = this; - return loadOptionalLibrary("canvg") + return loadCanvg() .then( function(canvg) { return canvg.Canvg.fromString(ctx, svg, options);