[v4-breaking] Propose new exporting API for better ESM & Typescript support
I was looking into fixing some of the autoTable is not defined issues and improving ESM support, and also typescript issues, It all came down to the hack we do to apply the plugin to the current jspdf instance, we are using require() here to wrap it with a try-catch, this cannot be transpiled to import so it causes a problem with rollup in some version of vite/vue/angular and requires setting a flag (https://github.com/vitejs/vite/issues/5759)
The solution
I propose we don't apply the plugin to jsPDF, we don't even supply applyPlugin(), so there will be no doc.autoTable* we just export the functions needed to work on a jspdf doc, currently there's autoTable(doc, ...) we make this the only way and export any other function needed like setDefaults(), so the proposed API is like this :
// ESM imports
import { jsPDF } from 'jspdf'
import { autoTable } from 'jspdf-autotable'
// commonjs (node)
const { jsPDF } = require('jspdf')
const { autoTable } = require('jspdf-autotable')
// in the browser (with a <script> tag)
const { jsPDF } = window.jspdf
const { autoTable } = window['jspdf-autotable']
// Usage
const doc = new jsPDF()
const table = autoTable(doc, {/* options */})
doc.save()
// you can access anything regarding the created table
table.finalY
table.pageNumber
table.settings
// ...
// no applyPlugin()
// no jsPDF.autoTable*
// no jsPDF.lastAutoTable
// other autotable exported functions
import { autoTable, setDefaults, htmlToJson } from 'jspdf-autotable'
setDefaults({/* ... */})
htmlToJson(/* ... */)
What makes this a breaking change is instead of default export import autoTable from 'jspdf-autotable' we change to named exports import { autoTable } from 'jspdf-autotable' to allow us to export other parts like setDefault so we don't need to extend jspdf (doc.autoTable*) and importing become consistent in all environments, That's actually also what jspdf did from v1 to v2 :
// v1
import jsPDF from "jspdf";
// v2
import { jsPDF } from "jspdf";
The benefits
This solves many problems :
- No need for any
require()hacks, so the source code is pure ESM which makes it much easier to transpile to any format without problems (fixes #860 and many more). - The new API is fully ESM compliant and tree-shakable with a suitable build (fixes #706).
- Consistent usage between all environments, and only one way to create the table.
- Ability to use any version of
jspdf, you just pass thedoccreated toautoTable. - Solves the typescript
(doc as any).autoTableproblem (#994, #848) because we won't extend jspdf, we just import the correctdoctype from jspdf and use it, and we have a type for the returned table which can be used to access any info regarding the table likefinalYso no need fordoc.lastAutotable
The downside
- No ease of use in the browser where you could just link the script and
doc.autoTable(). - This is a breaking change so will need a major version bump (v4?)
But we could use this opportunity and remove the deprecated parts and improve the other parts, we can study the other improvements that could be done, if some need API breaking changes we do it so we don't have to do breaking changes again in the future.
@simonbengtsson What do you think? I'm ready to tackle this, if this is going to happen, I think we should create a v4 branch, do all the work there and merge when we are ready. but first I'll work a bit on the current version, go through the issues, fix what I can and take notes of things need breaking changes to do it in v4.
Sounds great! Time for a proper modernization! 🎉
I played around with this a bit now in the newly pushed v4 branch and I think I were able to implement everything exactly as your proposal above @mmghv. Great stuff!
- Only the
autoTable(doc, {...})usage style is now supported anddoc.autoTable({...})has been removed - Removed setting default options as this can just as easily and with more flexibility be done outside of the plugin
- Removed old deprecations
Remaining is also to change so that autoTable returns a Table instance and remove assignment of jspdf.lastAutotable etc. Something else you have thought of @mmghv?
Sorry been busy for a while, just need one week to finish a task then I'll test & review the changes along with the list of todos I was planning for v4, I was hopping to take the chance to plan any breaking changes we need to do for other features/fixes/changes to introduce with this major version bump.
Sounds great. No rush 👍
Really looking forward to this as my dev environment broke with one of the last vite updates... If I can help testing, let me know 👍
We currently target ES5 when transpiling, is it time to upgrade to ES6 (ES2015) with v4? I hate seeing all the vars and .prototype stuff especially in the es build.
ES6 adds support for const/let, classes, arrow functions and more, this results in a cleaner and a little bit smaller code:
| Output file | ES5 size | ES6 size |
|---|---|---|
| jspdf.plugin.autotable.js | 85KB | 75KB |
| jspdf.plugin.autotable.min.js | 33KB | 28KB |
| jspdf.plugin.autotable.mjs | 76KB | 71KB |
But IE11 doesn't fully support ES6: https://caniuse.com/?search=es6
I'm not actually sure if jsPDF or autoTable fully supports IE11, and everyone is dropping support for it. @simonbengtsson what do you think?
Sounds good to me! If there is anyone who still supports IE11 they can always tick with v3.
Hey @hrueger, you can test v4 right now to verify that it solves the problem you're having with v3. First, verify that you still have a problem with v3 in your dev environment then do the following:
1- Clone the v4 repo:
git clone -b v4 https://github.com/simonbengtsson/jsPDF-AutoTable.git
2- Edit package.json of autotable and change the name field to "jspdf-autotable4"
3- Link autotable v4 as a global package, inside the repo run:
npm link
4- Inside your project, install the linked v4 package:
npm link jspdf-autotable4
Now you can test v4 in your project, just remember to import from jspdf-autotable4:
import { jsPDF } from 'jspdf'
import { autoTable } from 'jspdf-autotable4'
const doc = new jsPDF()
const table = autoTable(doc, {/* options */})
console.log(table.finalY)
doc.save()
After you're done testing, unlink the v4 package, Inside your project, run these two commands:
npm unlink --global jspdf-autotable4
npm unlink jspdf-autotable4
Hi @mmghv, thanks for the detailed instructions. I tested it and it works just fine 👍
@hrueger Forgot to add instructions to build the dist files because they were not updated yet, the module system should have worked with you but the return table (table.finalY) shouldn't.
Either re-clone the repo or run npm install and npm run build in the v4 repo to build the new dist files.
If the module system is all you wanted to test and it solved your problem then you don't have to do anything else.
Thanks for taking the time to test v4!
@mmghv Thanks for the clarification. I actually did not follow your instructions one by one, because I had some trouble with yarn link (I'm not using npm in my project). So I checked out the v4 branch, used npm run build and npm pack to generate a .tgz file and installed that in my project. Therefore, I'm pretty sure I already tested with the latest changes 👍
table.finalY also worked fine.
@hrueger Great! thanks for taking the time 👍