How to enable tree shaking?
vdboor opened this issue · 11 comments
Somehow tree shaking isn't working for me. I end up with a JavaScript file of 40kB when I do:
import { Alert, Collapse } from 'bootstrap.native';
Doing the equivalent in Bootstrap 5 JS will give me a 13kB file:
import { Alert } from 'bootstrap/js/src/alert.js';
import { Collapse } from 'bootstrap/js/src/collapse.js';
WebPack is configured with:
{
mode: 'production',
optimization: {
usedExports: true, // tree shaking
minimize: true,
minimizer: [
new TerserPlugin(),
]
}
}
And my package.json
has "sideEffects": false
in it.
Is there anything I'm still doing wrong, or is this a bug in the package?
As a sidenote, I would have loved to use the old approach of importing from sub files directly. This is no longer possible due to the exports
section in package.json
.
Yes, this happened during the Rollup => Vite migration. If I could find a solution, will let you know.
Please test @5.0.12 and let me know.
Tree shaking isn't working with esbuild also. Is there any workaround to import only selected components from library?
I will have to redo the entire tooling for this, build individual components and export them separately in package.json
Is this on schedule already?
Not at this time, no.
@thednp This doesn't seem to work for me. This code worked before and still works:
import { Toast } from "bootstrap.native";
const toast = Toast.getInstance(toastEl);
// toast is initialized
However the treeshaken version does not work:
import Toast from "bootstrap.native/toast";
const toast = Toast.getInstance(toastEl);
// toast is null
I've verified that the code stepped through the Toast constructor first in both examples.
I've even combined them in one example (during an htmx load event):
import htmx from "htmx.org/dist/htmx.esm.js";
import { Toast as DestructuredToast } from "bootstrap.native";
import TreeShakenToast from "bootstrap.native/toast";
htmx.onLoad((rootEl) => {
rootEl.querySelectorAll(".toast").forEach((toastEl) => {
let destructuredToast = DestructuredToast.getInstance(toastEl);
let treeShakenToast = TreeShakenToast.getInstance(toastEl);
console.log({ destructuredToast, treeShakenToast });
});
});
I can obviously do a null-check and construct it again but that shouldn't be necessary I guess.
Note: We use esbuild for bundling.
Another note: Since we're using HTMX, we use the initCallback
method to initialise BSN on injected DOM content, like so:
import * as BSN from "bootstrap.native";
htmx.onLoad((el) => {
// not necessary on initial load (DOMContentLoaded)
if (el !== document.body) {
BSN.initCallback(el);
}
});
Since initCallback
isn't "treeshakeable", I guess there's no real use for us to treeshake individual components in other places, since we'd still have the whole of BSN bundled by this import?
Is your project a typescript based project? You might need to restart your Typescript server.
I tried playing around with tsup, might be a good solution for this multi exports tree-shake enabled feature.
Anyways, I'm open to any suggestion.
@thednp No, it's JS (with htmx). Hope to convert it to TS soon but still to discuss with other team members. We added BSN to benefit for other additional features. Would that matter anyhow (apart from maybe the import * as BSN from ...
statements)?
You can try, but I believe using Vite and Typescript will ensure the file loader is in place to handle these separate exports. There could also be some properties missing in your package.json, you might have to check on that.
Just FYI: I installed BSN in a separate project, initialized with Tooltip and it worked out of the box, keep in mind that project is using an identical Typescript and Vite tooling setup.