evanw / esbuild

An extremely fast bundler for the web
https://esbuild.github.io/
MIT License
38.22k stars 1.16k forks source link

Question: is there a way to drop specific exports? #3890

Open fregante opened 3 months ago

fregante commented 3 months ago

I'm bundling a library that has about a hundred small exports, each followed by "inline test data" that should not be shipped to production.

I'm currently using --drop-labels=TEST and a helper function like TEST: addTest('name', [data]) but it feels a bit delicate because then I also have to make sure addTest is dropped, etc.

My full command is:

esbuild index.ts --bundle --external:github-reserved-names --format=esm --drop-labels=TEST

Ideally, this is what it'd write:

export const something = 23456;
export const something_TEST_DATA = [data]

And esbuild would provide a way to drop *_TEST_DATA exports. Unfortunately labels are not allowed before exports

Context: https://github.com/refined-github/github-url-detection/pull/196/files?file-filters%5B%5D=.json&file-filters%5B%5D=.ts&file-filters%5B%5D=.yml&show-viewed-files=true&show-deleted-files=false

fregante commented 3 months ago

If tree-shaking works, I think it would be "as easy as" using a different entry-point like:

export {something, other, stuff} from './lib.js';

so that all unused test data is tree-shaken, but this becomes impractical and dangerous when there are a hundred exports and you forget to add new ones to this entry-point.

hyrious commented 3 months ago

I'm not sure why you're exporting a test-only data from the source code. Maybe it will be used in another script?

Anyway, I come up with 2 possible solutions:

fregante commented 3 months ago

I'm not sure why you're exporting a test-only data from the source code. Maybe it will be used in another script?

Yes, the test script uses import * as stuff and then the stuff array can be easily filtered by _TEST_DATA name.

I'm actually already using my "ideal" version in another project, but it works there because it's not a library (i.e. the other exports are imported by the production code, and the test exports are naturally tree-shaken)

Source with test code: https://github.com/refined-github/refined-github/blob/13510c32340b53fc0532e00f6b90a687bf1279bb/source/github-helpers/selectors.ts#L5-L10 Tests with filter: https://github.com/refined-github/refined-github/blob/13510c32340b53fc0532e00f6b90a687bf1279bb/source/github-helpers/selectors.test.ts#L60

  • a JavaScript label can have a block follows:

That's actually my current solution, as mentioned in my second paragraph. It works, but I'm looking for alternatives, ideally via exports since it works well in my other project.

  • The export names can always be scaned with es-module-lexer or something like that

I suppose that would require writing a esbuild plugin, which is less ideal than the current label-based solution.