jsPDF-AutoTable icon indicating copy to clipboard operation
jsPDF-AutoTable copied to clipboard

[v4-breaking] Propose new exporting API for better ESM & Typescript support

Open mmghv opened this issue 2 years ago • 15 comments

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 :

  1. 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).
  2. The new API is fully ESM compliant and tree-shakable with a suitable build (fixes #706).
  3. Consistent usage between all environments, and only one way to create the table.
  4. Ability to use any version of jspdf, you just pass the doc created to autoTable.
  5. Solves the typescript (doc as any).autoTable problem (#994, #848) because we won't extend jspdf, we just import the correct doc type 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 like finalY so no need for doc.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.

mmghv avatar Sep 28 '23 18:09 mmghv

Sounds great! Time for a proper modernization! 🎉

simonbengtsson avatar Sep 29 '23 19:09 simonbengtsson

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 and doc.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

simonbengtsson avatar Feb 02 '24 23:02 simonbengtsson

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?

simonbengtsson avatar Feb 08 '24 15:02 simonbengtsson

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.

mmghv avatar Feb 08 '24 21:02 mmghv

Sounds great. No rush 👍

simonbengtsson avatar Feb 08 '24 21:02 simonbengtsson

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 👍

hrueger avatar Feb 14 '24 15:02 hrueger

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?

mmghv avatar Feb 22 '24 11:02 mmghv

Sounds good to me! If there is anyone who still supports IE11 they can always tick with v3.

simonbengtsson avatar Feb 23 '24 10:02 simonbengtsson

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

mmghv avatar Feb 28 '24 01:02 mmghv

Hi @mmghv, thanks for the detailed instructions. I tested it and it works just fine 👍

hrueger avatar Feb 29 '24 08:02 hrueger

@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 avatar Feb 29 '24 11:02 mmghv

@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 avatar Feb 29 '24 12:02 hrueger

@hrueger Great! thanks for taking the time 👍

mmghv avatar Feb 29 '24 13:02 mmghv