Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cli option to disable bundling #1461

Closed
wants to merge 5 commits into from

Conversation

taylorcode
Copy link
Collaborator

@taylorcode taylorcode commented Jul 28, 2020

Depends on the fix in #1460

Copied from #1390 (comment):

pbjs generates a single bundle of JS for all of the transitive .protos. Therefore if you run pbjs on proto A and then proto B, and both depend on C, then you'll end up with two copies of C's generated JS code -- a.js will contain it, as well as b.js. This is a problem if you need to load proto A and B on the same page for two reasons:

  • code bloat - you're loading C's code twice. If you need to load many protos and they share dependencies, you'll end up with an explosion of duplicate code.

  • orphaned object references - because of the way protobuf creates the roots data structure at runtime, every time C is loaded into memory it replaces the previous instance of C. Therefore you can potentially end up with references to different instances of C. Practically I'm not sure what issues this could cause but best to be avoided.

To work around this you could use pbjs to generate one bundle of JS bundle per page, but this isn't ideal for two reasons:

  • http caching - if two pages both need C's code, then ideally you have one copy of it that can be shared.
  • on-demand loading - if you only have one bundle then you can't load parts of it as needed.

You could also generate one bundle for all pages, but this does not scale.

The fact that pbjs bundles at all is a little weird. The protoc tool doesn't do this for any language, including JS. And even for web browsers this isn't ideal for the reasons stated. If bundling is needed, asset bundlers (e.g. rollup / webpack) should be used for this.

Example

my/protos/c.proto

package my_protos_c;

message C {
   string some_field = 1;
}

my/protos/a.proto

package my_protos_a;
import "my/protos/c.proto";

message A {
  my_proto_c.C nested_msg_c = 1;
}

my/protos/b.proto

package my_protos_b;
import "my/protos/c.proto";

message B {
   my_proto_c.C nested_msg_c = 1;
}

Strategy 1: run pbjs on each proto
pbjs --target static-module --out a.js a.proto
pbjs --target static-module --out b.js b.proto

import {my_protos_a} from 'my/protos/a';
import {my_protos_b} from 'my/protos/b';

page loads C's code twice

Strategy 2: generate one js bundle per page with pbjs
pbjs --target static-module --out page_1.js a.proto
pbjs --target static-module --out page_2.js b.proto

page 1

import {my_protos_a} from 'my/protos/page_1';

page 2

import {my_protos_b} from 'my/protos/page_2';

page 1 loads different copy of C than page 2

Strategy 3: generate one .js file for every .proto

pbjs --target static-module --path out/ --no-bundle a.proto
pbjs --target static-module --path out/ --no-bundle b.proto
pbjs --target static-module --path out/ --no-bundle c.proto

import {my_protos_a} from 'my/protos/a';
import {my_protos_b} from 'my/protos/b';

only 1 copy of C is loaded

page 1

import {my_protos_a} from 'my/protos/page_1';

page 2

import {my_protos_b} from 'my/protos/page_2';

page 1 loads same copy of C as page 2

@taylorcode taylorcode changed the title Add ability to disable bundling Add cli option to disable bundling Jul 28, 2020
@taylorcode
Copy link
Collaborator Author

taylorcode commented Jul 16, 2021

Superseded by #1634

@taylorcode taylorcode closed this Jul 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants